对 DOM 的两个主要的扩展是 Selectors API(选择符 API)和 HTML5。
一、选择符API
1、querySelector()方法
querySelector() 方法接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null 。
//取得 body 元素
var body = document.querySelector("body");
//取得 ID 为"myDiv"的元素
var myDiv = document.querySelector("#myDiv");
//取得类为"selected"的第一个元素
var selected = document.querySelector(".selected");
//取得类为"button"的第一个图像元素
var img = document.body.querySelector("img.button");
通过 Document 类型调用 querySelector() 方法时,会在文档元素的范围内查找匹配的元素。而通过 Element 类型调用 querySelector() 方法时,只会在该元素后代元素的范围内查找匹配的元素。
CSS 选择符可以简单也可以复杂,视情况而定。如果传入了不被支持的选择符, querySelector()会抛出错误。
2、querySelectorAll()方法
querySelectorAll() 方法接收的参数与 querySelector() 方法一样,都是一个 CSS 选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个 NodeList 的实例。
能够调用 querySelectorAll() 方法的类型包括 Document 、DocumentFragment 和 Element 。
//取得某<div>中的所有<em>元素(类似于 getElementsByTagName("em"))
var ems = document.getElementById("myDiv").querySelectorAll("em");
//取得类为"selected"的所有元素
var selecteds = document.querySelectorAll(".selected");
//取得所有<p>元素中的所有<strong>元素
var strongs = document.querySelectorAll("p strong");
3、matchesSelector()方法
matchesSelector()方法接收一个参数,即 CSS 选择符,如果调用元素与该选择符匹配,返回 true ;否则,返回 false 。
if (document.body.matchesSelector("body.page1")){
//true
}
还没有浏览器支持 matchesSelector() 方法;
二、元素遍历
三、HTML5
1、与类相关的扩充
(1) getElementsByClassName() 方法
可以通过 document对象及所有 HTML 元素调用该方法。
getElementsByClassName() 方法接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的 NodeList 。传入多个类名时,类名的先后顺序不重要。
//取得所有类中包含"username"和"current"的元素,类名的先后顺序无所谓
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得 ID 为"myDiv"的元素中带有类名"selected"的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");
在 document 对象上调用getElementsByClassName() 始终会返回与类名匹配的所有元素,在元素上调用该方法就只会返回后代元素中匹配的元素。
(2) classList 属性
在操作类名时,需要通过 className 属性添加、删除和替换类名。
<div class="bd user disabled">...</div>
//删除"user"类
//首先,取得类名字符串并拆分成数组
var classNames = div.className.split(/\s+/);
//找到要删的类名
var pos = -1,
i,
len;
for (i=0, len=classNames.length; i < len; i++){
if (classNames[i] == "user"){
pos = i;
break;
}
}
//删除类名
classNames.splice(i,1);
//把剩下的类名拼成字符串并重新设置
div.className = classNames.join(" ");
这个 <div> 元素一共有三个类名。要从中删除一个类名,需要把这三个类名拆开,删除不想要的那个,然后再把其他类名拼成一个新字符串。
HTML5 新增了一种操作类名的方式,可以让操作更简单也更安全,那就是为所有元素添加classList 属性。新类型定义如下方法:
- add(value) :将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
- contains(value) :表示列表中是否存在给定的值,如果存在则返回 true ,否则返回 false 。
- remove(value) :从列表中删除给定的字符串。
- toggle(value) :如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。
代替上例多行代码:
div.classList.remove("user");
其它例子:
//删除"disabled"类
div.classList.remove("disabled");
//添加"current"类
div.classList.add("current");
//切换"user"类
div.classList.toggle("user");
//确定元素中是否包含既定的类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
//执行操作
)
//迭代类名
for (var i=0, len=div.classList.length; i < len; i++){
doSomething(div.classList[i]);
}
2、焦点管理
HTML5 添加了辅助管理 DOM 焦点的功能。
document.activeElement 属性始终会引用 DOM 中当前获得了焦点的元素。
元素获得焦点的方式有页面加载、用户输入(通常是通过按 Tab 键)和在代码中调用 focus() 方法。
var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button); //true
新增了 document.hasFocus() 方法用于确定文档是否获得了焦点。
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true
通过检测文档是否获得了焦点,可以知道用户是不是正在与页面交互。
3、HTMLDocument的变化
(1) readyState 属性
Document 的 readyState 属性有两个可能的值:
- loading ,正在加载文档;
- complete ,已经加载完文档。
使用 document.readyState 的最恰当方式,就是通过它来实现一个指示文档已经加载完成的指示器。
基本用法:
if (document.readyState == "complete"){
//执行操作
}
(2)兼容模式
自从 IE6 开始区分渲染页面的模式是标准的还是混杂的,检测页面的兼容模式就成为浏览器的必要功能。IE 为此给 document 添加了一个名为 compatMode 的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。就像下面例子中所展示的那样,在标准模式下,document.compatMode 的值等于 "CSS1Compat" ,而在混杂模式下, document.compatMode 的值等于 "BackCompat" 。
if (document.compatMode == "CSS1Compat"){
alert("Standards mode");
} else {
alert("Quirks mode");
}
后来,其它浏览器陆续实现这个属性。
4、字符集属性
charset 属性表示文档中实际使用的字符集,也可以用来指定新字符集。
alert(document.charset); //"UTF-16"
document.charset = "UTF-8";
另一个属性是 defaultCharset ,表示根据默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么。
5、自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀 data- ,目的是为元素提供与渲染无关的信息,或者提供语义信息。
添加了自定义属性之后,可以通过元素的 dataset 属性来访问自定义属性的值。 dataset 属性的值是 DOMStringMap 的一个实例,也就是一个名值对儿的映射。
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
var div = document.getElementById("myDiv");
//取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//设置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
//有没有"myname"值呢?
if (div.dataset.myname){
alert("Hello, " + div.dataset.myname);
}
6、插入标记
(1) innerHTML 属性
在读模式下, innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的 HTML 标记。在写模式下, innerHTML 会根据指定的值创建新的 DOM树,然后用这个 DOM 树完全替换调用元素原先的所有子节点。
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<!-- 对于上面的元素来说,它的 innerHTML 属性会返回如下字符串。 -->
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
并不是所有元素都支持 innerHTML 属性。
(2) outerHTML 属性
在读模式下, outerHTML 返回调用它的元素及所有子节点的 HTML 标签。在写模式下, outerHTML会根据指定的 HTML 字符串创建新的 DOM子树,然后用这个 DOM 子树完全替换调用元素。
(3) insertAdjacentHTML() 方法
insertAdjacentHTML() 方法接收两个参数:插入位置和要插入的 HTML 文本。
第一个参数必须是下列值之一:
- "beforebegin" ,在当前元素之前插入一个紧邻的同辈元素;
- "afterbegin" ,在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
- "beforeend" ,在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
- "afterend" ,在当前元素之后插入一个紧邻的同辈元素。
//作为前一个同辈元素插入
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>");
四、专有扩展
1、文档模式
文档模式决定了你可以使用哪个级别的 CSS,可以在 JavaScript 中使用哪些 API,以及如何对待文档类型(doctype)。
没有规定说必须在页面中设置 X-UA-Compatible 。默认情况下,浏览器会通过文档类型声明来确定是使用最佳的可用文档模式,还是使用混杂模式。
通过 document.documentMode 属性可以知道给定页面使用的是什么文档模式。
2、children属性
children 属性与 childNodes 没有什么区别,即在元素只包含元素子节点时,这两个属性的值相同。
var childCount = element.children.length;
var firstChild = element.children[0];
3、contains()方法
contains() 方法查找某个节点是不是另一个节点的后代。这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,该方法返回 true ;否则,返回 false 。
alert(document.documentElement.contains(document.body)); //true
compareDocumentPosition() 也能够确定节点间的关系。这个方法用于确定两个节点间的关系,返回一个表示该关系的位掩码( bitmask)。