在JavaScript中从单个节点创建节点列表
这是其中一个看起来很简单的问题,但我想不出一个好办法 我有一个节点,可能是在JavaScript中从单个节点创建节点列表,javascript,nodes,nodelist,Javascript,Nodes,Nodelist,这是其中一个看起来很简单的问题,但我想不出一个好办法 我有一个节点,可能是nodelist=document.getElementById(“mydiv”)-我需要将其规范化为节点列表。也不是数组:一个真实的节点列表对象 非nodelist=[document.getElementById(“mydiv”) 请不要使用库。如果您的目标浏览器支持,它将始终返回节点列表。因此: var nodelist = document.querySelectorAll("#mydiv"); 获取JavaSc
nodelist=document.getElementById(“mydiv”)代码>-我需要将其规范化为节点列表。也不是数组:一个真实的节点列表对象
非nodelist=[document.getElementById(“mydiv”)代码>
请不要使用库。如果您的目标浏览器支持,它将始终返回节点列表。因此:
var nodelist = document.querySelectorAll("#mydiv");
获取JavaScript中已经引用的任何元素,给它一个我们可以使用选择器找到的属性,将其作为列表查找,删除该属性,然后返回列表
function toNodeList(elm){
var list;
elm.setAttribute('wrapNodeList','');
list = document.querySelectorAll('[wrapNodeList]');
elm.removeAttribute('wrapNodeList');
return list;
}
从bfavaretto的回答延伸而来
现在
重新启用它是因为我最近想起了一些关于JavaScript的内容。这取决于节点列表的检查方式,但是
constsinglenode=((nodeList)=>(node)=>{
const layer={//定义我们的特定案例
0:{value:node,可枚举:true},
长度:{value:1},
项目:{
价值(一){
还这个[+i||0];
},
可枚举:正确,
},
};
return Object.create(nodeList,layer);//将我们的案例放在真正的nodeList之上
})(document.createDocumentFragment().childNodes);//一个真正的节点列表
现在,如果你这样做了
const list = singleNode(document.body); // for example
list instanceof NodeList; // true
list.constructor === NodeList; // true
并且list
具有属性length1
和0作为节点,以及从NodeList继承的任何内容
如果您不能使用Object.create
,则除了作为具有原型nodelist
的构造函数并设置此['0']=节点外,您还可以执行相同的操作代码>,此['length']=1编码>并使用new
创建
ES5版本
var singleNode = (function () {
// make an empty node list to inherit from
var nodelist = document.createDocumentFragment().childNodes;
// return a function to create object formed as desired
return function (node) {
return Object.create(nodelist, {
'0': {value: node, enumerable: true},
'length': {value: 1},
'item': {
"value": function (i) {
return this[+i || 0];
},
enumerable: true
}
}); // return an object pretending to be a NodeList
};
}());
另一种基于Reflect.construct的方法是:
与其他情况一样,它需要修补NodeList.prototype.item才能调用此函数
NodeList.prototype.item = function item(i) {
return this[+i || 0];
};
let nl = Reflect.construct(Array, [], NodeList);
要使用节点创建它,请将节点数组作为第二个参数传递。
此方法通过以下检查:
list instanceof NodeList; // true
list.constructor === NodeList; // true
使用它创建的数组可以使用for..of
、forEach
和其他标准方法,您可以使用simplenl[n]=node向其中添加元素代码>非常相似的可能重复项。。。实现略有不同。很高兴在这里有这样的参考。考虑到我的答案有问题,你能不能取消接受我的答案,以便我删除它?想法也不错,但这并不总是我得到我的节点的方式+1对于其他可能发现相关和有用的想法!你是说你不能用任何CSS选择器访问你想要的元素?是的。节点可以是动态创建的或从文档中选择的。@RandyHall edit几乎可以在任何情况下工作(elm.nodeType!==1除外),因此基本上,如果它在文档或上下文容器中,请执行您的方法,否则,David Thomas的方法将是安全的。很好。在大多数情况下,你是完全正确的。但我必须利用其他人编写的函数,但不能影响这一要求,并特别检查节点列表。还要指出的是,如果你想使用list.item
,你必须对其进行阴影处理,以避免非法调用(可能使用两级原型)。我很感激这几年来,为什么singleNode
返回一个自执行函数?在创建空的DocumentFragment
之后,只返回对象就可以了。创建…
?不管调用多少次,文档片段都只创建一次吗?@RegularJo-yep,当我们将文档片段放入原型中而不修改它时,如果我们在为ES6ButnodeList instanceof nodeList
返回false的scopeUpdated中捕获相同的片段,我们可以重复使用相同的片段很多次。您可以像这样附加后返回nodeList:console.log(nodeList.childNodes instanceof nodeList);//返回true
问题是将节点添加到片段会将其从文档DOM中删除。我不确定项声明和+I
语法(以前从未见过),但Reflect.construct()工作得很好。我收回了它……在Safari 12中我们得到了它“TypeError:Reflect.construct要求第三个参数是构造函数(如果存在)”。那么,您可以尝试使用它:div.parentNode.querySelectorAll(:scope>:第n个子项(${Array.from(div.parentNode.children).indexOf(div)+1})
)不确定是否与Safari 12兼容,并且它肯定不会在IE11中工作,但它会返回实际的节点列表。但元素必须有父元素。如果parentNode为null,可以通过临时将其添加到另一个元素中来解决。
const list = singleNode(document.body); // for example
list instanceof NodeList; // true
list.constructor === NodeList; // true
var singleNode = (function () {
// make an empty node list to inherit from
var nodelist = document.createDocumentFragment().childNodes;
// return a function to create object formed as desired
return function (node) {
return Object.create(nodelist, {
'0': {value: node, enumerable: true},
'length': {value: 1},
'item': {
"value": function (i) {
return this[+i || 0];
},
enumerable: true
}
}); // return an object pretending to be a NodeList
};
}());
NodeList.prototype.item = function item(i) {
return this[+i || 0];
};
let nl = Reflect.construct(Array, [], NodeList);
list instanceof NodeList; // true
list.constructor === NodeList; // true