何时NodeList是实时的,何时是静态的?

83

来自 MDN 关于 NodeList 的说明:

在某些情况下,NodeList 是一个实时集合,这意味着 DOM 中的更改会反映在该集合中。例如,Node.childNodes 是实时的:

 var parent = document.getElementById('parent');
 var child_nodes = parent.childNodes;
 console.log(child_nodes.length); // let's assume "2"
 parent.appendChild(document.createElement('div'));
 console.log(child_nodes.length); // should output "3"
在其他情况下,NodeList是一个静态集合,这意味着DOM中的任何后续更改都不会影响集合的内容。document.querySelectorAll返回一个静态NodeList。 所以......有点烦人!是否有任何中央参考资料可以查看哪些方法返回实时列表,哪些返回静态列表,而无需逐个检查DOM API的所有各个部分?这里有什么规则在起作用吗?

请查看NodeList.js - Edwin Reynoso
2个回答

147

关于每个方法是否为实时的信息已在详细介绍中,但似乎没有确定标准。

document.getElementsByClassName() 是一个 HTMLCollection,并且是实时的。
document.getElementsByTagName() 是一个 HTMLCollection,并且是实时的。
document.getElementsByName() 是一个 NodeList,并且是实时的。
document.querySelectorAll() 是一个 NodeList,并且不是实时的。
HTMLCollection 似乎总是实时的。

http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75708506

因此,始终存在于 DOM 中的是 HTML 集合,而 NodeList 是更通用的构造,可能存在于 DOM 中,也可能不存在于其中。

http://www.w3.org/TR/DOM-Level-3-Core/core.html#td-live

听起来不错,对吧?

http://www.w3.org/TR/2012/WD-dom-20120405/#collections

因此,规范会指示静态集合。所以,按照这个逻辑,document.querySelectorAll() 是一个集合,但它不在 DOM 中。因为虽然集合可能是实时的也可能不是,但在 DOM 中的集合必须是实时的... 这种区别并不是特别有用。

好吧,这里有一种快速方法来确定 collection 是否为实时的; 它将集合的成员的克隆体添加到 DOM 中(以匹配选择器),检查长度是否发生变化,然后将其删除(以使页面不受影响)。

演示

function isLive(collection) {
    if (HTMLCollection.prototype.isPrototypeOf(collection)) return true // HTMLCollections are always live

    const length = collection.length;
    if (!length) return undefined; // Inconclusive

    const el = collection.item(0);
    const parent = el.parentNode;
    const clone = el.cloneNode();

    clone.style.setProperty('display', 'none', 'important');
    parent.appendChild(clone);

    const live = collection.length !== length;
    parent.removeChild(clone);
    return live;
}

const divs1 = document.getElementsByClassName('c');
const divs2 = document.getElementsByTagName('span');
const divs3 = document.getElementsByName('notFound');
const divs4 = document.querySelectorAll('.c');

console.log("document.getElementsByClassName('c'):", divs1.toString()); //   [object HTMLCollection]
console.log("document.getElementsByTagName('notFound'):", divs2.toString()); //  [object HTMLCollection]
console.log("document.getElementsByName('notFound'):", divs3.toString()); // [object NodeList]
console.log("document.querySelectorAll('.c'):", divs4.toString()); //        [object NodeList]

console.log('isLive(divs1)', isLive(divs1)); // true
console.log('isLive(divs2)', isLive(divs2)); // true
console.log('isLive(divs3)', isLive(divs3)); // undefined
console.log('isLive(divs4)', isLive(divs4)); // false
<html>
    <body>
        <div>
            <div class="c">C1</div>
            <div class="c">C2</div>
        </div>
        <div>
            <div class="c">C3</div>
            <div class="c">C4</div>
        </div>
    </body>
</html>


4
我不确定是否有一个中央参考,但这些是我知道的返回HTMLCollection和live NodeList的方法和属性:
方法
- parentNode.getElementsByClassName() - 返回一个HTMLCollection - parentNode.getElementsByTagName() - 返回一个HTMLCollection - parentNode.getElementsByTagNameNS() - 返回一个HTMLCollection - document.getElementsByName() - 返回一个NodeList
属性
- parentNode.children - 返回一个HTMLCollection - Node.childNodes - 返回一个NodeList

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接