web-dev-qa-db-fra.com

Comment convertir une liste de nœuds DOM en un tableau en Javascript?

J'ai une fonction Javascript qui accepte une liste de nœuds HTML, mais elle attend un tableau Javascript (il exécute quelques méthodes Array là-dessus) et je veux lui donner la sortie de Document.getElementsByTagName qui renvoie une liste de nœuds DOM.

Au départ, j'ai pensé à utiliser quelque chose de simple comme:

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

Et cela fonctionne très bien dans tous les navigateurs, sauf bien sûr Internet Explorer qui renvoie l'erreur "Objet JScript attendu", comme apparemment la liste des nœuds DOM retournée par Document.getElement* méthodes n'est pas un objet JScript suffisant pour être la cible d'un appel de fonction.

Mises en garde: cela ne me dérange pas d'écrire du code spécifique à Internet Explorer, mais je ne suis pas autorisé à utiliser des bibliothèques Javascript telles que JQuery parce que j'écris un widget à intégrer dans un site Web tiers, et je ne peux pas charger des bibliothèques externes qui créera un conflit pour les clients.

Mon dernier effort est de parcourir la liste des nœuds DOM et de créer moi-même un tableau, mais existe-t-il une meilleure façon de le faire?

81
Guss

Les NodeLists sont Objets hôtes, en utilisant Array.prototype.slice la méthode sur les objets Host n'est pas garantie de fonctionner, la spécification ECMAScript indique:

La réussite de l'application de la fonction tranche à un objet Host dépend de l'implémentation.

Je vous recommande de créer une fonction simple pour parcourir le NodeList et ajouter chaque élément existant à un tableau:

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;
}

MISE À JOUR:

Comme d'autres réponses le suggèrent, vous pouvez désormais utiliser dans les environnements modernes la syntaxe étendue ou le Array.from méthode:

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

Mais en y réfléchissant, je suppose que le cas d'utilisation le plus courant pour convertir une NodeList en tableau est d'itérer dessus, et maintenant le NodeList.prototype l'objet a la méthode forEach en mode natif , donc si vous êtes dans un environnement moderne, vous pouvez l'utiliser directement ou avoir un pollyfill.

48
CMS

Dans es6 , vous pouvez simplement utiliser comme suit:

  • Opérateur de diffusion

     var elements = [... nodelist]
    
  • En utilisant Array.from

     var elements = Array.from(nodelist)
    

plus de référence sur https://developer.mozilla.org/en-US/docs/Web/API/NodeList

110
camiloazula

En utilisant spread (ES2015) , c'est aussi simple que: [...document.querySelectorAll('p')]

(facultatif: utilisez Babel pour transpiler le code ES6 ci-dessus en syntaxe ES5)


Essayez-le dans la console de votre navigateur et voyez la magie:

for( links of [...document.links] )
  console.log(links);
16
vsync

Utilisez cette astuce simple

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

Bien que ce ne soit pas vraiment un shim approprié, car aucune spécification ne nécessite de travailler avec des éléments DOM, j'en ai créé un pour vous permettre d'utiliser slice() de cette manière: https: // Gist .github.com/brettz9/6093105

[~ # ~] mise à jour [~ # ~] : Quand j'ai soulevé cela avec l'éditeur de la spécification DOM4 (demandant s'ils pouvaient ajouter leurs propres restrictions aux objets hôtes (pour que la spécification oblige les implémenteurs à convertir correctement ces objets lorsqu'ils sont utilisés avec des méthodes de tableau) au-delà de la spécification ECMAScript qui avait permis l'indépendance d'implémentation), il a répondu que "les objets hôtes sont plus ou moins obsolètes par ES6/IDL . " Je vois par http://www.w3.org/TR/WebIDL/#es-array que les spécifications peuvent utiliser cet IDL pour définir des "objets de tableau de plate-forme" mais http: // www.w3.org/TR/domcore/ ne semble pas utiliser le nouvel IDL pour HTMLCollection (bien qu'il semble que ce soit le cas pour Element.attributes bien qu'il ne le fasse que indique explicitement qu'il utilise WebIDL pour DOMString et DOMTimeStamp). Je vois que [ArrayClass] (Qui hérite de Array.prototype) est utilisé pour NodeList (et NamedNodeMap est maintenant déconseillé au profit du seul élément qui l'utiliserait encore, Element.attributes). Dans tous les cas, il semble que cela devienne standard. L'ES6 Array.from Pourrait également être plus pratique pour de telles conversions que d'avoir à spécifier Array.prototype.slice Et plus sémantiquement clair que [].slice() (et la forme plus courte, Array.slice() (un "tableau générique"), pour autant que je sache, n'est pas devenu un comportement standard).

6
Brett Zamir
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));
  }
}

Cela devrait fonctionner, traverser le navigateur et obtenir tous les nœuds "élément".

3
Strelok

Aujourd'hui, en 2018, nous pourrions utiliser ECMAScript 2015 (6e édition) ou ES6, mais tous les navigateurs ne peuvent pas le comprendre (par exemple IE ne comprend pas tout). Si vous voulez vous pouvez utiliser ES6 comme suit: var array = [... NodeList]; (comme opérateur d'étalement) ou var array = Array.from(NodeList);.

Dans les autres cas (si vous ne pouvez pas utiliser ES6), vous pouvez utiliser le moyen le plus court pour convertir un NodeList en Array:

var array = [].slice.call(NodeList, 0);.

Par exemple:

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">

Mais si vous voulez parcourir simplement la liste des nœuds DOM facilement, vous n'avez pas besoin de convertir un NodeList en Array. Il est possible de parcourir les éléments dans un NodeList en utilisant:

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">

Ne soyez pas tenté d'utiliser for...in ou - for each...in pour énumérer les éléments de la liste, car cela énumérera également la longueur et les propriétés d'élément du NodeList et provoquera des erreurs si votre script suppose qu'il ne doit traiter que des objets élément. De plus, for..in N'est pas garanti de visiter les propriétés dans un ordre particulier. for...of les boucles boucleront correctement sur les objets NodeList.

Voir aussi:

3
Bharata