NodeList.js rend l'utilisation des API DOM natives sur un Array de Nodes aussi simple que jQuery avec les avantages d'être extrêmement petit, à environ 4k minifiés , et le navigateur en tant que dépendance (c'est la partie la plus intéressante) .
La première chose que vous remarquerez est que j'utilise $$ , la raison pour laquelle j'ai choisi cela pour sélectionner DOM Nodes est que si vous ouvrez vos outils de développement et tapez ce qui suit :
$$ ( 'div' ) ; // Will return a NodeListNodeList.js : HTML que nous allons manipuler comme suit : < body >
< div id =" container " class =" cont " >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
< div class =" child " > </ div >
</ div >
</ body > #container : Chacun des éléments suivants renvoie un Array of Nodes (AKA my NodeList , pas la NodeList native du navigateur)
// Method 1
$$ ( '#container div' ) ;
// Method 2
$$ ( '#container' ) . children ;
// Method 3
$$ ( 'div div' ) ;Si vous transmettez une chaîne de requête, vous pouvez transmettre un deuxième argument comme portée :
let container = document . getElementById ( 'container' ) ;
$$ ( 'div' , container ) ;Ce qui équivaudrait à :
// Just this doesn't return my NodeList, but the browser's NodeList
container . querySelectorAll ( 'div' ) ; Vous pouvez passer des nœuds comme arguments :
$$(document, document.body); // returns NodeList
Vous pouvez également passer 1 Array de nœuds ou une NodeList ou une HTMLCollection qui ne sera pas aplatie, pour aplatir utilisez concat() :
$$([document, document.body]); // returns NodeList
Node :Comment procéderiez-vous normalement :
let children = document . getElementsByClassName ( 'child' ) ; Vous obtiendrez maintenant les propriétés sur les enfants du #container :
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . id ; // ''
children [ i ] . nodeName ; // 'DIV'
children [ i ] . className ; // 'child'
} Voici comment procéder avec nodeList.js :
$$ ( '.child' ) . id ; // ['', '' ... x10]
$$ ( '.child' ) . nodeName ; // ['DIV', 'DIV' ... x10]
$$ ( '.child' ) . className ; // ['child', 'child' ... x10] Par conséquent, vous liriez chaque propriété comme vous le feriez avec un seul Node :)
Remarquez comment il renvoie un Array de la valeur de la propriété, ce qui signifie que vous pouvez les sélectionner par index et utiliser n'importe quelle Array Methods dessus, vous verrez lorsque vous arriverez à la partie en boucle.
node : Continuons à utiliser la variable children , voici donc comment définir les propriétés des children :
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . className = 'containerChild' ;
children [ i ] . textContent = 'This is some text' ;
} Voici comment procéder avec NodeList.js :
$$ ( '.child' ) . className = 'containerChild' ;
$$ ( '.child' ) . textContent = 'This is some text' ; node : Toujours en utilisant la variable children :
Ajoutons un écouteur d'événement à chaque nœud, même si event delegation serait la meilleure solution, mais pour le bien de cet exemple :
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ;
} Voici comment procéder avec NodeList.js :
$$ ( '.child' ) . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ; Tellement cool, non ? Vous pouvez utiliser n'importe quelle Native DOM method :
Définissons quelques attributs :
$$ ( '.child' ) . setAttribute ( 'class' , 'child div' ) ;
// For setting the class you could just do:
$$ ( '.child' ) . className = 'child div' ;En cliquant sur les éléments :
$$ ( '.child' ) . click ( ) ;Suppression des éléments :
$$ ( '.child' ) . remove ( ) ; Je pense que vous comprenez le point : n'importe quelle Native DOM Method dont chaque Node/Element hérite, vous pouvez simplement appeler la NodeList et elle sera appelée sur chaque élément.
BTW : toutes les méthodes DOM qui renverraient normalement undefined lorsqu'elles sont appelées sur un seul Node renverront la même NodeList pour permettre le chaînage de méthodes. Comme setAttribute() .
Utiliser une boucle for et ES6 for-of :
Nous allons simplement supprimer les nœuds du DOM à titre d'exemple :
let nodes = $$ ( '.child' ) ;
for ( let i = 0 , l = nodes . length ; i < l ; i ++ ) {
nodes [ i ] . remove ( ) ;
}
for ( let node of nodes ) {
node . remove ( ) ;
} Utilisation de forEach :
// Removes all Nodes and returns same the NodeList to allow method chaining
$$ ( '.child' ) . forEach ( function ( node ) {
node . remove ( ) ;
} ) ;
// But Just do:
$$ ( '.child' ) . remove ( ) ;Parcourir les propriétés :
// Returns Array of style objects (CSSStyleDeclaration)
let styles = $$ ( '.child' ) . style ;
for ( let i = 0 , l = styles . length ; i < l ; i ++ ) {
styles [ i ] . color = 'red' ;
}
for ( let style of styles ) {
style . color = 'red' ;
}
styles . forEach ( function ( style ) {
style . color = 'red' ;
} ) ;
// OR loop through the nodes themselves
let nodes = $$ ( '.child' ) ;
for ( let i = 0 , l = nodes . length ; i < l ; i ++ ) {
nodes [ i ] . style . color = 'red' ;
}
for ( let node of nodes ) {
node . style . color = 'red' ;
}
nodes . forEach ( function ( node ) {
node . style . color = 'red' ;
} ) ; // Returns NodeList containing first Node
$$ ( '.child' ) . slice ( 0 , 1 ) ; Le mappage est facile, il suffit d'obtenir la propriété comme vous le feriez sur un seul nœud
// Returns an Array of the id of each Node in the NodeList
$$ ( '#container' ) . id ;
// No need for
$$ ( '#container' ) . map ( function ( element ) {
return element . id ;
} ) ;
// Map() Checks if Array is fully populated with nodes so returns a NodeList populated with firstChld nodes
$$ ( '#container div' ) . map ( function ( div ) {
return div . firstChild ;
} ) ;
// Maps the firstChild node and removes it, and returns the NodeList of firstChild Nodes
$$ ( '#container' ) . map ( function ( div ) {
return div . firstChild ;
} ) . remove ( ) ;
// Or:
$$ ( '#container' ) . firstChild . remove ( ) ; // Filter out the #container div
$$ ( 'div' ) . filter ( function ( div ) {
return ! div . matches ( '#container' ) ;
} ) ; Je ne pouvais pas penser à un meilleur exemple pour utiliser Réduire sur une NodeList (mais c'est possible)
let unique = $$ ( 'div' ) . reduce ( function ( set , div ) {
set . add ( div . parentElement ) ;
return set ;
} , new Set ( ) ) ; Il y a aussi reduceRight()
Les méthodes concat() suivantes renvoient toutes une nouvelle NodeList concaténée (n'affectant pas la NodeList sur laquelle concat() est appelée)
let divs = $$ ( 'div' ) ;
// Method 1 passing a Node
let divsAndBody = divs . concat ( document . body ) ;
// Method 2 passing an Array of Nodes
let divsAndBody = divs . concat ( [ document . body ] ) ;
// Method 3 passing a NodeList
let divsAndBody = divs . concat ( $$ ( 'body' ) ) ;
// Method 4 passing an Array of NodeList
let divsAndBody = divs . concat ( [ $$ ( 'body' ) ] ) ;
// Method 5 passing multiple Nodes as arguments
let divsAndBodyAndHTML = divs . concat ( document . body , document . documentHTML ) ;
// Method 6 passing multiple Arrays of Nodes as arguments
let divsAndBodyAndHTML = divs . concat ( [ document . body ] , [ document . documentHTML ] ) ;
// Method 7 passing multiple Arrays of NodeList as are arguments
let divsAndBodyAndHTML = divs . concat ( [ $$ ( 'body' ) ] , [ $$ ( 'html' ) ] ) ; Concat() est récursif, vous pouvez donc transmettre un Array aussi profond que vous le souhaitez.
Maintenant, si vous transmettez quelque chose qui n'est pas un Node , NodeList , HTMLCollections , Array ou Array of Arrays contenant autre chose qu'un Node , NodeList , HTMLCollections , Array générera une Error .
let divs = $$ ( 'div' ) ;
// Pushes the document.body element, and returns the same NodeList to allow method chaining.
divs . push ( document . body ) ; let divs = $$ ( 'div' ) ;
// Removes last Node in the NodeList and returns a NodeList of the removed Nodes
divs . pop ( ) ; pop() prend un argument facultatif indiquant le nombre Nodes à POP
// Removes last 2 Nodes in the NodeList and returns a NodeList of the removed Nodes
divs . pop ( 2 ) ; let divs = $$ ( 'div' ) ;
// Removes first Node in the NodeList and returns a NodeList of the removed Nodes
divs . shift ( ) ; shift() prend également un argument facultatif indiquant le nombre Nodes à SHIFT.
// Removes first 2 Nodes in the NodeList and returns a NodeList of the removed Nodes
divs . shift ( 2 ) ; let divs = $$ ( 'div' ) ;
// Inserts/unshifts the document.body into the beginning of the NodeList and returns the same NodeList to allow method chaining.
divs . unshift ( document . body ) ; Remplaçons le premier élément qui serait #container par document.body
let divs = $$ ( 'div' ) ;
// Removes the first Element, inserts document.body in its place and returns a NodeList of the spliced Nodes
divs . splice ( 0 , 1 , document . body ) ; let divs = $$ ( '.child' ) ;
// Gives each div a data-index attribute
divs . forEach ( function ( div , index ) {
div . dataset . index = index ;
} ) ;
// Reverse the NodeList and returns the same NodeList
divs . sort ( function ( div1 , div2 ) {
return div2 . dataset . index - div1 . dataset . index ;
} ) ; // Returns the same NodeList, but reversed
$$ ( 'div' ) . reverse ( ) ; Je n'ai pas mis de méthode join pour NodeLists car cela serait inutile sur les nœuds réels :
// Returns "[object HTMLDivElement], [object HTMLDivElement] ..."
$$ ( '.child' ) . join ( ) ;Par conséquent, vous pouvez toujours l'utiliser lors du mappage des propriétés :
// Returns "child,child,child,child,child,child,child,child,child,child"
$$ ( '.child' ) . className . join ( ) ; // Returns true if passed Node is included in the NodeList
$$ ( 'body' ) . includes ( document . body ) ; // Returns body element: <body>
$$ ( 'body' ) . find ( function ( el ) {
return el === el ;
} ) ; // Returns 0
$$ ( 'body' ) . findIndex ( function ( el ) {
return el === el ;
} ) ; Il se peut qu'il y ait des méthodes DOM qui porteront le même nom que celles de Array.prototype à l'avenir, ou vous souhaiterez peut-être simplement convertir la NodeList en un Array que vous pourrez donc utiliser comme Array natif :
asArray $$ ( 'body' ) . asArray ; // returns Array
$$ ( 'body' ) . asArray . forEach ( function ( ) { ... } ) ; // uses native Array method therefore you cannot chain Ok, que diriez-vous maintenant de traiter des éléments qui ont des propriétés uniques. Comme HTMLAnchorElement(s) ils ont la propriété href qui n'est pas héritée de HTMLElement . Il n'y a pas HTMLAnchorElements dans cet exemple, mais voici comment vous allez le gérer.
// Returns undefined because it's a unique property that every element does not inherit
$$ ( 'a' ) . href
// Returns an Array of href values
$$ ( 'a' ) . get ( 'href' ) ; Get() peut également être utilisé sur un Array de propriétés :
// Returns an Array of the value of each node.style.color
$$ ( '.child' ) . style . get ( 'color' ) ; // Sets the href property of each Node in NodeList
$$ ( 'a' ) . set ( 'href' , 'https://www.example.com/' ) ; set() définira uniquement les propriétés sur les Nodes dont les propriétés ne sont pas indéfinies :
$$ ( 'div, a' ) . set ( 'href' , 'https://www.example.com/' ) ; href ne sera défini que sur les éléments <a> et non sur les <div> s
set() peut également être utilisé sur un Array de propriétés :
// Sets each element's color to red and returns the Array of styles back
$$ ( '.child' ) . style . set ( 'color' , 'red' ) ;Vous pouvez également définir plusieurs propriétés :
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) ;Idem avec les propriétés mappées :
$$ ( '.child' ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ;N'oubliez pas que vous pouvez enchaîner :
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ; Il existe des méthodes propres à certains éléments. Voici comment appeler ces méthodes :
$$ ( 'video' ) . call ( 'pause' ) ;Ou vous pouvez simplement parcourir les éléments et appeler les méthodes
Qu'en est-il du passage d'arguments :
// Returns Array of `CanvasRenderingContext2D`
$$ ( 'canvas' ) . call ( 'getContext' , '2d' ) ; Si la méthode appelée sur l'un des éléments renvoie quelque chose, un Array de ces éléments renvoyés sera renvoyé par call() sinon la NodeList sera renvoyée pour permettre le chaînage des méthodes.
La méthode native item(index) du navigateur fait la même chose que NodeList[index] mais dans la mienne, elle renvoie ce Node en tant que ma NodeList (si vous connaissez jQuery c'est la même chose que la méthode eq() de jQuery)
// returns the <html> element
$$ ( 'html, body' ) [ 0 ] ;
// returns my NodeList [<html>]
$$ ( 'html, body' ) . item ( 0 ) ; Ceci afin que vous puissiez continuer à utiliser les mêmes propriétés/méthodes de ma NodeList, au lieu d'avoir à slice le seul Node
owner : Tout ce que fait la propriété propriétaire, c'est vous renvoyer la NodeList à partir de laquelle la propriété a été mappée :
var elms = $$ ( '.child' ) ;
elms . style . owner === elms ; // trueJe peux donc faire toutes sortes de choses :
N'oubliez pas que style de mappage renvoie un Array de CSSStyleDeclarations
$$ ( '.child' ) . style ; Cela vous rendra la NodeList à partir de laquelle style a été mappé :
var childs = $$ ( '.child' ) ;
childs . style . owner === childs ; // true Si vous connaissez jQuery c'est la même chose que sa propriété prevObj
$$ . NL . myMethod = function ( ) {
// You'll have to write your own loop here if you want to call this on each Node or use:
this . forEach ( function ( node ) {
// do something with each node
} ) ;
}| Navigateur | Version |
|---|---|
| FireFox | 6+ |
| Safari | 5.0.5+ |
| Chrome | 6+ |
| IE | 9+ |
| Opéra | 11+ |
Attention : vous devez réaliser que ma bibliothèque dépend du navigateur qu'elle exécute (ce qui est génial, donc elle se met automatiquement à jour lorsque le navigateur met à jour le DOM avec de nouvelles propriétés/méthodes) ce qui signifie : disons que la propriété hidden n'existe pas dans le navigateur. API DOM que vous ne pouvez pas faire : $$('.child').hidden = true;