DOM扩展

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-12-15

虽然DOM为与XMLHTML文档交互制定了一系列核心API,但仍然有几个规范对标准的DOM进行了扩展。这些扩展中有很多原来是浏览器专有的,但后来成为了事实标准,于是其他浏览器也都提供了相同的实现。

一、选择符API

querySelector方法

接收一个CSS选择符(字符串),返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null

通过Document类型调用querySelector方法时,会在文档元素的范围内查找匹配的元素。而通过Element 类型调用,只会在该元素后代元素的范围内查找匹配的元素。如果传入了不被支持的选择符,会抛出错误。

querySelectorAll方法

接收的参数与querySelector方法一样,都是一个CSS选择符,但返回的是所有匹配的元素而不仅仅是一个元素。返回的值实际上是带有所有属性和方法的NodeList。如果没有找到匹配的元素,NodeList就是空的。如果传入了不被支持的选择符,会抛出错误。

二、元素遍历

  • childElementCount:返回子元素的个数(不包括文本节点和注释)。
  • firstElementChild:指向第一个子元素;firstChild 的元素版。
  • lastElementChild:指向最后一个子元素;lastChild 的元素版。
  • previousElementSibling:指向前一个同辈元素;previousSibling 的元素版。
  • nextElementSibling:指向后一个同辈元素;nextSibling 的元素版。

三、HTML5与DOM 节点相关部分

classList 属性

在操作类名时,需要通过className属性添加、删除和替换类名。因为className中是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值。

因此,HTML5为所有元素添加了classList属性。这个classList属性是新集合类型DOMTokenList的实例。与其他DOM集合类似,DOMTokenList有一个表示己包含多少元素的length属性,而要取得每个元素可以使用item()方法,也可以使用方括号语法。此外,这个新类型还定义如下方法。

  • add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
  • contains(value):表示列表中是否存在给定的值,如果存在则返回true,否则返回false
  • remove(value):从列表中删除给定的字符串。
  • toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。

焦点管理

HTML5也添加了辅助管理DOM焦点的功能。首先就是document.activeElement属性,这个属性始终会引用DOM中当前获得了焦点的元素。元素获得焦点的方式有页面加载、用户输入(通常是通过按Tab键)和在代码中调用focus()方法。

默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素的引用。文档加载期间,document.activeElement的值为null

另外就是新增了document.hasFocus()方法,这个方法用于确定文档(页面)是否获得了焦点。通过检测文档是否获得了焦点,可以知道用户是不是正在与页面交互。

var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true

HTMLDocument的变化

1、readyState属性

DocumentreadyState属性有两个可能的值:

  • "loading",正在加载文档;
  • "complete",已经加载完文档。

使用document.readyState的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器。在这个属性得到广泛支持之前,要实现这样一个指示器,必须借助onload事件处理程序设置一个标签,表明文档已经加载完毕。

if (document.readyState == "complete"){
    //文档已经加载完成 执行操作
}

2、兼容模式

自从IE6 开始区分渲染页面的模式是标准的还是混杂的,检测页面的兼容模式就成为浏览器的必要功能。IE 为此给document添加了一个名为compatMode的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。在标准模式下,document.compatMode 的值等于"CSS1Compat",而在混杂模式下,document.compatMode的值等于"BackCompat"

3、head 属性

HTML5新增了document.head属性,引用文档的<head>元素。要引用文档的<head>元素,可以结合使用这个属性和另一种后备方法。

var head = document.head || document.getElementsByTagName("head")[0];
// 实现document.head 属性的浏览器包括Chrome 和Safari 5。

4、charset 字符集属性

HTML5 新增了几个与文档字符集有关的属性。其中,charset属性表示文档中实际使用的字符集,也可以用来指定新字符集。默认情况下,这个属性的值为"UTF-16",但可以通过<meta>元素、响应头部或直接设置charset属性修改这个值。

alert(document.charset); //"UTF-16"
document.charset = "UTF-8";

5、自定义数据属性

HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以data-开头即可。

添加了自定义属性之后,可以通过元素的dataset属性来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,也就是一个名值对儿的映射。在这个映射中,每个data-name形式的属性都会有一个对应的属性,只不过属性名没有data-前缀(比如,自定义属性是data-myname,那映射中对应的属性就是myname)。

需要注意的是,所有的data-后面的 key 值,所有的驼峰写法会被转换为连续的小写,所有的-线分隔会被转换成驼峰写法。

<div id="myDiv" data-appId="12345" data-my-name="Nicholas"></div>

<script>
  var div = document.getElementById("myDiv");

  //取得自定义属性的值
  var appId = div.dataset.appId; 
  console.log(appId); // 取不到值 undefined

  var appId = div.dataset.appid; // 大写都会被转变为小写
  console.log(appId); // 12345

  var myName = div.dataset.myName; // -横线分隔会被转换成驼峰
  console.log(myName); // Nicholas

  //设置值
  div.dataset.appId = 23456; // 设置不了 因为转换成了 appid
  div.dataset.myName = "Jack";

  if (div.dataset.myName){
    alert("Hello, " + div.dataset.myName + " " +  div.dataset.appid); // Hello, jack 12345
  }
</script>

插入标记

1、innerHTML 属性

在读模式下返回与调用元素的所有子节点,在写模式下会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。在大多数浏览器中,通过innerHTML插入<script>元素并不会执行其中的脚本。

2、outerHTML属性

在读模式下,返回调用它的元素(包含调用元素本身)以及所有子节点的HTML标签。在写模式下,outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。

3、insertAdjacentHTML方法

将指定的文本解析为HTMLXML,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接innerHTML操作更快。

它接收两个参数:插入位置和要插入的HTML文本。第一个参数必须是下列值之一:

//作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
//作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//作为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");

4、内存与性能问题

在删除带有事件处理程序或引用了其他JavaScript对象子树时,就有可能导致内存占用问题。假设某个元素有一个事件处理程序(或者引用了一个JavaScript对象作为属性),在使用前述innerHTMLouterHTML属性将该元素从文档树中删除后,**元素与事件处理程序(或JavaScript对象)之间的绑定关系在内存中并没有一并删除。**如果这种情况频繁出现,页面占用的内存数量就会明显增加。因此,在使用innerHTMLouterHTML 属性和insertAdjacentHTML方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性

不可避免地,创建和销毁HTML解析器也会带来性能损失,所以最好能够将设置innerHTMLouterHTML的次数控制在合理的范围内,所以要尽量避免下面这种操作。

// 要避免这种频繁操作!!
for (var i=0, len=values.length; i < len; i++){
  ul.innerHTML += "<li>" + values[i] + "</li>"; 
}

// 可以先将单独构建字符串,之后一次把结果字符串赋值给innerHTML

var itemsHtml = "";   
for (var i=0, len=values.length; i < len; i++){
  itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;

scrollIntoView方法

scrollIntoView可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。接收一个布尔值参数,默认为true,窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入false,调用元素会尽可能全部出现在视口中,可能的话,调用元素的底部会与视口顶部平齐,不过顶部不一定平齐。

// 让元素可见
document.forms[0].scrollIntoView();