html 如何在Javascript中将DOM节点列表转换为数组?

zy1mlcev  于 2023-05-21  发布在  Java
关注(0)|答案(7)|浏览(123)

我有一个Javascript函数,它接受一个HTML节点列表,但它需要一个Javascript数组(它在上面运行一些Array方法),我想把Document.getElementsByTagName的输出提供给它,它返回一个DOM节点列表。
最初,我想用一些简单的东西,比如:

Array.prototype.slice.call(list,0)

这在所有浏览器中都可以正常工作,当然除了Internet Explorer,它返回错误“JScript object expected”,因为显然Document.getElement*方法返回的DOM节点列表不是一个JScript对象,不足以成为函数调用的目标。
警告:我不介意编写Internet Explorer特定的代码,但我不允许使用任何Javascript库,如JQuery,因为我正在编写一个嵌入到第三方网站的小部件,我不能加载外部库,这将为客户端创建冲突。
我最后的努力是迭代DOM节点列表并自己创建一个数组,但是有更好的方法吗?

tvmytwxo

tvmytwxo1#

es6中,您可以使用如下命令:

  • 扩展算子
var elements = [... nodelist]
  • 使用Array.from
var elements = Array.from(nodelist)

更多参考资料在https://developer.mozilla.org/en-US/docs/Web/API/NodeList

ghhaqwfi

ghhaqwfi2#

NodeList是 host objects,在host objects上使用Array.prototype.slice方法不能保证工作,ECMAScript规范规定:
slice函数能否成功应用于宿主对象取决于实现。
我建议你编写一个简单的函数来迭代NodeList,并将每个现有元素添加到数组中:

function toArray(obj) {
  var array = [];
  // iterate backwards ensuring that length is an UInt32
  for (var i = obj.length >>> 0; i--;) { 
    array[i] = obj[i];
  }
  return array;
}

更新:

正如其他答案所建议的那样,您现在可以在现代环境中使用spread语法或Array.from方法:

const array = [ ...nodeList ] // or Array.from(nodeList)

但是仔细想想,我想将NodeList转换为Array最常见的用例是迭代它,现在NodeList.prototype对象有forEach method natively,所以如果你在现代环境中,你可以直接使用它,或者使用pollyfill。

niknxzdl

niknxzdl3#

使用spread (ES2015)非常简单:[...document.querySelectorAll('p')]

(可选:使用Babel将上述ES6代码转换为ES5语法)

  • 在您的浏览器控制台中尝试一下,看看它的魔力:*
for( links of [...document.links] )
  console.log(links);
zte4gxcn

zte4gxcn4#

使用这个简单的技巧

<Your array> = [].map.call(<Your dom array>, function(el) {
    return el;
})
jdzmm42g

jdzmm42g5#

今天,在2018年,我们可以使用ECMAScript 2015(第6版)或ES6,但并非所有浏览器都能理解它(例如,ECMAScript 2015)。我不明白所有的一切)。如果你愿意,你可以使用ES6如下:var array = [... NodeList];as spread operator)或**var array = Array.from(NodeList);**。
在其他情况下(如果你不能使用ES6),你可以使用最短的方法将NodeList转换为Array
var array = [].slice.call(NodeList, 0);

例如:

var nodeList = document.querySelectorAll('input');
//we use "{}.toString.call(Object).slice(8, -1)" to find the class name of object
console.log({}.toString.call(nodeList).slice(8, -1)); //NodeList

var array = [].slice.call(nodeList, 0);
console.log({}.toString.call(array).slice(8, -1)); //Array

var result = array.filter(function(item){return item.value.length > 5});

for(var i in result)
  console.log(result[i].value); //credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

但是,如果您只想简单地迭代DOM节点列表,则不需要将NodeList转换为Array。可以使用以下命令循环NodeList中的项目:

var nodeList = document.querySelectorAll('input');
// Calling nodeList.item(i) isn't necessary in JavaScript
for(var i = 0; i < nodeList.length; i++)
    console.log(nodeList[i].value); //trust, credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

不要尝试使用**for...infor each...in来枚举列表中的项,因为这也会枚举NodeList的长度和项属性,如果脚本假定它只需要处理元素对象,则会导致错误。此外,for..in不保证以任何特定的顺序访问这些属性。for...of**循环将正确循环NodeList对象。

请参见:

8e2ybdfx

8e2ybdfx6#

虽然它不是一个真正合适的shim,因为没有规范要求使用DOM元素,但我已经做了一个,允许您以这种方式使用slice()https://gist.github.com/brettz9/6093105

更新:当我向DOM 4规范的编辑提出这个问题时(询问他们是否可以在ECMAScript规范允许实现独立性的基础上,为主机对象添加自己的限制(以便规范要求实现者在与数组方法一起使用时正确转换这些对象)),他回答说“主机对象在ES6 / IDL中或多或少已经过时了。”我在www.example.com上看到http://www.w3.org/TR/WebIDL/#es-arrayspecs可以使用这个IDL来定义“平台数组对象”,但是http://www.w3.org/TR/domcore/似乎没有为HTMLCollection使用新的IDL(尽管它看起来可能会为Element.attributes这样做,尽管它只显式地声明它正在为DOMString和DOMTimeStamp使用WebIDL)。我确实看到[ArrayClass](继承自Array.prototype)被用于NodeList(而NamedNodeMap现在被弃用,以支持唯一仍在使用它的项目Element.attributes)。无论如何,它看起来都将成为标准。ES6 Array.from也可能比指定Array.prototype.slice更方便进行此类转换,并且比[].slice()在语义上更清晰(据我所知,更短的形式Array.slice()(“数组泛型”)尚未成为标准行为)。

xqnpmsa8

xqnpmsa87#

var arr = new Array();
var x= ... get your nodes;

for (i=0;i<x.length;i++)
{
  if (x.item(i).nodeType==1)
  {
    arr.push(x.item(i));
  }
}

这应该工作,跨浏览器,并得到你所有的“元素”节点。

相关问题