DOM部分扩展

对DOM的两个主要扩展是Selectors API和HTML5。javascript

选择符API

Selectors API致力于让浏览器原生支持CSS查询。在没有原生支持以前,只能经过javascript代码来完成查询操做。以后,解析和树查询操做能够在浏览器内部经过编译后的代码来完成,极大地改善了性能。java

querySelector()方法

querySelector()方法接收一个CSS选择符,返回与该模式匹配的第一个元素,若是没有找到匹配的元素,返回null。node

经过Document类型调用时,会在文档元素的范围内查找匹配的元素。而经过Element类型调用时,只会在该元素后代元素的范围内查找匹配的元素。web

<ul>
    <li class='one'></li>
    <li></li>
    <li></li>
</ul>

$ul = document.querySelector('ul');

$ul.querySelector('.one')
// return <li class='one'></li>
复制代码

querySelectorAll()方法

querySelectorAll()方法接收的参数与querySelector()方法同样,都是一个CSS选择符,但返回的时全部匹配的元素。这个方法返回的时一个Nodelist实例。浏览器

<ul>
    <li class='one'></li>
    <li></li>
    <li></li>
</ul>

$ul = document.querySelector('ul');

$ul.querySelectorAll('.two')
// NodeList[]
复制代码

能够调用上面两种方法的node类型包括:document、element、DocumentFragment。安全

matchesSelector()方法

Element类型新增了一个方法matchesSelector()。这个方法接收了一个参数,即CSS选择符,若是调用元素与该选择符匹配,返回true;不然,返回false。bash

这个方法尚未被全部浏览器都支持。app

元素遍历

专门用于element类型的元素遍历dom

  • childElementCount
  • firstElementChild
  • lastElementChild
  • perviousElementSibling
  • nextElementSibling

HTML5

HTML5规范则围绕如何使用新增标记定义了大量Javascript API。其中一些API和DOM重叠,定义了浏览器应该支持的DOM扩展。函数

与类相关的扩充

getElementsByClassName()方法

这个方法能够经过document对象以及全部HTML元素调用。

classList属性

在操做类名时,须要经过className属性添加、删除和替换类名。由于className中是一个字符串,因此即便只修改字符串的一部分,也必须每次都设置整个字符串的值。

<div class='a b c'></div>
var className = div.className.split(/\s+/);
var pos = -1;
var i;
var len;
for (i=0, len=className.length; i < len; i++) {
    if (className[i] == 'a') {
        pos = i;
        break;
    }
}

//删除类名
className.splice(i, 1)

//把剩下的类名拼成字符串并从新设置
div.className = className.join(' ');
复制代码

HTML5新增了一种操做类名的方式,可让操做更简单也更安全,那就是为全部元素添加classList属性。这个classList属性是新集合类型DOMTokenList的实例。
DOMTokenList有一个表示本身包含多少元素的length属性,而要取得每一个元素可使用item()方法,也可使用方括号语法。此外这个新类型还定义以下方法。

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

焦点管理

document.activeElement属性,这个属性始终引用了DOM中当前得到了焦点的元素。元素得到焦点的方式有页面加载、用户输入和在代码中调用focus()方法。

var dom = document.getElementById('dom');

dom.focus();

document.activeElement === dom;  // true
dom.hasFocus();  // true
复制代码

HTMLDocument变化

添加readyState属性

Document的readyState属性有两个可能的值:

  • loading,正在加载文档
  • complete,已经加载文档 document.readyState属性的基本用法以下:
if(document.readyState === 'complete') {
    // 执行操做
}
复制代码

head属性

新增document.body方法,直接引用元素

字符集属性

HTML5新增了几个与文档字符集有关的属性。其中,charset属性表示文档中实际使用的字符集,也能够用来指定新字符集。

自定义数据属性

HTML5规定能够为元素添加非标准的属性,但要添加前缀data-。

var dom = `<div id='myDiv' data-appid='234' data-myname='zc'></div>`;
var $container = document.createElement('div');
$container.innerHTML = dom;
var $dom = $container.firstElementChild;

$dom.dataset; // DOMStringMap {appid: "234", myname: "zc"}

$dom.dataset.appid = 12;

$dom.dataset; // DOMStringMap {appid: "12", myname: "zc"}
复制代码

插入标记

使用插入标记的技术,直接插入HTML字符串不只更简单,速度也更快。如下与插入标记相关的DOM扩展已经归入了HTML5规范。

innerHTML属性

在读模式下,innerHTML属性返回与调用元素的全部子节点(包括元素、注释和文本节点)对应的HTML标记。在写模式下,innerHTML会根据指定的值建立新的DOM树,而后用这个DOM树彻底替换调用元素原先的全部子节点。

可是,不一样浏览器返回的文本格式会有所不一样。IE和Opera会将全部标签转换成大写形式。而Safari、Chrome和Firefox则会原本来本地按照原先文档中的格式指定返回HTML,包括空格和缩进。

在写模式下,innerHTML的值会被解析为DOM子树,替换调用元素原来的全部子节点。由于它的值被认为是HTML,因此其中的全部标签都会按照浏览器处理HTML的标准方式转换为元素。

为innerHTML设置HTML字符串后,浏览器会将这个字符串解析为相应的DOM树。所以设置了innerHTML以后,再从中读取HTML字符串,会获得与设置时不同的结果。缘由在于返回的字符串是根据原始HTML字符串建立的DOM树通过序列化以后的结果。

outerHTML属性

在读模式下,outerHTML返回调用它的元素及全部子节点的HTML标签。在写模式下,outerHTML会根据指定的HTML字符串建立新的DOM子树,而后用这个DOM子树彻底替换调用元素。

insertAdjacentHTML()方法

插入标记的最后一个新增方式是insertAdjacentHTML()方法。这个方法最先也是在IE中出现的,它接受两个参数:插入位置和要插入的HTML文本。第一个参数必须是下列值之一:

  • beforeBegin,在当前元素以前插入一个紧邻的同辈元素

内存与性能问题

使用本节介绍的方法替换子节点可能会致使浏览器的内存占用问题,尤为在IE中,问题更加明显。在删除带有事件处理程序或引用了其余Javascript对象子树时,就有可能致使内存占用问题。假设某个元素有一个事件处理程序(或者引用了一个javascript对象做为属性),在使用前述某个属性将该元素从文档树中删除后,元素与事件处理程序(javascript对象)之间的绑定关系在内存中并无一并删除。若是这种状况频繁出现,页面占用的内存数量就会明显增长。所以,在使用innerHTML、outerHTML、insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的全部事件处理程序和Javascript对象属性。

同理: 每次循环都设置一次innerHTML的作法效率很低。

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

效率更高的:

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

ul.innerHTML = itemsHTML;
复制代码

那些没有标准化的专用扩展

文档模式

IE8引入了一个新的概念叫作“文档模式”(document mode)。页面的文档模式决定了可使用什么功能。换句话说,文档模式决定了你可使用哪一个级别的CSS,能够在JavaScript中使用哪些API,以及如何对待文档类型(doctype)。到了IE9,总共有如下4种文档模式。

  • IE5: 以混杂模式渲染页面。
  • IE7: 以IE7标准模式渲染页面。IE8及更高版本中的新功能都没法使用。
  • IE8: 以IE8标准模式渲染页面。IE8中的新功能均可以使用,所以可使用Selectors API、更多CSS2选择符和某些CSS3功能,还有一些HTML5的功能。不过IE9中的新功能没法使用。
  • IE9:以IE9标准模式渲染页面。IE9中的新功能均可以使用,好比ECMAScript五、完整的CSS3以及更多HTML5功能。这种文档模式是最高级的模式。
<meta http-equiv='X-UA-Compatible' content='IE=IEVersion'>
复制代码

The http-equiv attribute is used by servers to gather information about a page using the HTTP header. The meta tag’s http-equiv attribute set is similar to a http header.

children属性

这个属性是HTMLCollection的实例,只包含元素中一样仍是元素的子节点。除此以外,children属性与childNodes没有什么区别。即在元素只包含元素子节点时,这两个属性的值相同。

contains方法

在实际开发中,常常须要知道某个节点是否是另外一个节点的后代。IE为此率先引入了contains()方法,以便不经过在DOM文档树中查找便可得到这个信息。调用contains()方法的应该是祖先节点,也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。若是被检测的节点是后代节点,该方法返回true;不然,返回false。

document.documentElement.contains(document.body);   // true
复制代码

使用DOM Level3 compareDocumentPosition()也可以肯定节点间的关系。这个方法用于肯定两个节点间的关系,返回一个表示关系的位掩码。

function contains (refNode, otherNode) {
    if (typeof refNode.contains == 'function' && (!client.engine.webkit || client.engine.webkit >= 522)) {
 return refNode.contains(otherNode);
    } else if (typeof refNode.compareDocumentPosition == "function") {
        return !!(refNode.compareDocumentPosition(otherNode) & 16);
    } else {
        var node = otherNode.parentNode;
        do {
            if(node === refNode) {
                return true;
            }
            node = node.parentNode;
        } while (node !== null);
        return false;
    }
}
复制代码

插入文本

前面介绍过,IE原来专有的插入标记的属性innerHTML和outerHTML已经被HTML5归入规范。但另外两个插入文本的专有属性则没有这么好的运气。这两个没有被HTML5看中的属性是innerText和outerText。

innerText属性

经过innerText属性能够操做元素中包含的全部文本内容,包括子文档树中的文本。在经过innerText读取值时,它会按照由浅入深的顺序,将子文档树中的全部文本拼接起来。在经过innerText写入值时,结果会删除元素的全部子节点,插入包含相应文本值的文本节点。
支持innerText属性的浏览器包括IE4+、safari 3+、Opera 8+和Chrome。Firefox虽然不支持innerText,但支持做用相似的textContent属性。textContent是DOM Level3规定的一个属性。为了确保跨浏览器兼容,有必要编写一个相似于下面的函数来检测可使用哪一个属性。

function getInnerText (element) {
    return (typeof element.textContent == 'string') ? element.textContent : element.innerText;
}

function setInnerText (element, text) {
    if (typeof element.textContent == 'string') {
        element.textContent = text;
    } else {
        element.innerText = text;
    }
}
复制代码

outerText属性

除了做用范围扩大到了包含调用它的节点以外,outerText与innerText基本上没有多大区别。

div.outerText = 'Hello World';
// 这行代码实际上至关于以下两行代码
var text = document.createTextNode('Hello World');

div.parentNode.replaceChild(text, div)
复制代码

滚动

HTML5以前的规范并无就与页面滚动相关的API作出相关规定。但HTML5在将scrollIntoView()归入规范以后,仍然还有其余几个专有方法能够在不一样的浏览器中使用。下面列出的几个方法都是对HTMLElement类型的扩展,所以在全部元素中均可以调用。

小结

本章主要介绍了一些DOM扩展:

  • Selectors API,定义了两个方法,让开发人员可以基于CSS选择符从DOM中取得元素,这两个方法是querySelector()和querySelectorAll()。
  • Element Traversal,为DOM元素定义了额外的属性,让开发人员可以更方便地从从一个元素跳到另外一个元素。之因此会出现这个扩展,是由于浏览器处理DOM元素间空白符的方式不同。
  • HTML5,为标准的DOM定义了不少扩展功能。
  • 等等
相关文章
相关标签/搜索