注意:在假设此问题是重复的之前,请查看本问题底部的一小节,解释为什么其他类似问题没有提供我所寻找的答案。
我们都知道将NodeList转换为数组很容易,并且有许多方法可以做到这一点:
[].slice.call(someNodeList)
// or
Array.from(someNodeList)
// etc...
我想要的是相反的情况;如何将节点数组转换为静态NodeList?
我为什么想这样做?
不深入讨论,我正在创建一种新方法来查询页面上的元素,例如:
Document.prototype.customQueryMethod = function (...args) {...}
为了保持与querySelectorAll
的工作方式一致,我希望返回一个静态集合NodeList
而不是一个数组。
到目前为止,我已经尝试了三种不同的方法来解决这个问题:
尝试 1:
创建文档片段
function createNodeList(arrayOfNodes) {
let fragment = document.createDocumentFragment();
arrayOfNodes.forEach((node) => {
fragment.appendChild(node);
});
return fragment.childNodes;
}
尽管这确实返回一个NodeList,但由于调用appendChild
会将节点从DOM中当前位置移除(而它应该留在原地),因此这种方法不起作用。
另一种变化涉及克隆(cloning)
节点并返回克隆的节点。然而,现在你返回的是克隆的节点,它们与DOM中实际节点没有任何引用关系。
尝试2:
试图“模拟”NodeList构造函数
const FakeNodeList = (() => {
let fragment = document.createDocumentFragment();
fragment.appendChild(document.createComment('create a nodelist'));
function NodeList(nodes) {
let scope = this;
nodes.forEach((node, i) => {
scope[i] = node;
});
}
NodeList.prototype = ((proto) => {
function F() {
}
F.prototype = proto;
return new F();
})(fragment.childNodes);
NodeList.prototype.item = function item(idx) {
return this[idx] || null;
};
return NodeList;
})();
并且它将会以以下方式被使用:
let nodeList = new FakeNodeList(nodes);
// The following tests/uses all work
nodeList instanceOf NodeList // true
nodeList[0] // would return an element
nodeList.item(0) // would return an element
虽然这种方法不会从DOM中删除元素,但它会导致其他错误,例如将其转换为数组时:
let arr = [].slice.call(nodeList);
// or
let arr = Array.from(nodeList);
以上每个都会产生以下错误:Uncaught TypeError: Illegal invocation
我还试图避免使用伪造的节点列表构造函数来“模仿”一个节点列表,因为我相信这将很可能带来未来的意外后果。
尝试3:
向元素附加临时属性以重新查询它们
function createNodeList(arrayOfNodes) {
arrayOfNodes.forEach((node) => {
node.setAttribute('QUERYME', '');
});
let nodeList = document.querySelectorAll('[QUERYME]');
arrayOfNodes.forEach((node) => {
node.removeAttribute('QUERYME');
});
return nodeList;
}
这一方法一直很有效,但我发现对于某些元素(例如SVG
),它却不起作用。尽管我只在Chrome中测试过,但它不会附加属性。
看起来这应该是一个容易解决的问题,但为什么我不能使用NodeList构造函数创建NodeList,并且为什么我不能像将NodeLists转换为数组那样以类似的方式将数组转换为NodeList?
如何正确地将节点数组转换为NodeList?
类似的问题有解决方案,但并不适用于我的问题:
以下问题与此问题相似。不幸的是,这些问题/答案并没有解决我的特定问题,原因如下。
如何将元素数组转换为NodeList? 这个问题中的答案使用了克隆节点的方法。这将不起作用,因为我需要访问原始节点。
在JavaScript中从单个节点创建节点列表使用了文档片段方法(第1次尝试)。其他答案在第2和第3次尝试中尝试类似的方法。
创建DOM NodeList正在使用E4X
,因此不适用。即使它使用了这个方法,它仍然会从DOM中删除元素。
querySelectorAll
返回一个数组。NodeList
唯一的优点在于它有可能是动态的,但实际意义不大。 - 4castle.childNodes
是一个动态的NodeList,而不是静态的。 - Bergi:scope
是不起作用的。我还尝试将find
原型方法添加到DocumentFragment
中,但也没有起作用。我使用了 这个答案 中的一些 polyfill 想法。 - KevBot