NodeList.js torna o uso de APIs DOM nativas em um Array de Nodes tão fácil quanto jQuery , com os benefícios de ser extremamente pequeno, em torno de 4k minificado , e o navegador como uma dependência (essa é a parte mais interessante) .
A primeira coisa que você notará é que estou usando $$ , a razão pela qual escolhi isso para selecionar DOM Nodes é porque se você abrir seu devtools e digitar o seguinte:
$$ ( 'div' ) ; // Will return a NodeListNodeList.js : HTML que manipularemos da seguinte forma: < 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 : Cada um dos itens a seguir retorna um Array of Nodes (também conhecido como my NodeList , não o NodeList nativo do navegador)
// Method 1
$$ ( '#container div' ) ;
// Method 2
$$ ( '#container' ) . children ;
// Method 3
$$ ( 'div div' ) ;Se você passar uma string de consulta, há um segundo argumento que você pode passar como escopo:
let container = document . getElementById ( 'container' ) ;
$$ ( 'div' , container ) ;O que seria equivalente a:
// Just this doesn't return my NodeList, but the browser's NodeList
container . querySelectorAll ( 'div' ) ; Você pode passar nós como argumentos:
$$(document, document.body); // returns NodeList
Você também pode passar 1 Array of Nodes ou um NodeList ou um HTMLCollection Não será nivelado, para nivelar use concat() :
$$([document, document.body]); // returns NodeList
Node :Como você faria normalmente:
let children = document . getElementsByClassName ( 'child' ) ; Agora você obteria propriedades nos filhos do #container :
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . id ; // ''
children [ i ] . nodeName ; // 'DIV'
children [ i ] . className ; // 'child'
} Veja como você faria isso com nodeList.js :
$$ ( '.child' ) . id ; // ['', '' ... x10]
$$ ( '.child' ) . nodeName ; // ['DIV', 'DIV' ... x10]
$$ ( '.child' ) . className ; // ['child', 'child' ... x10] Portanto, você leria cada propriedade da mesma forma que faria com um único Node :)
Observe como ele retorna um Array com o valor da propriedade, o que significa que você pode selecioná-los por index e usar qualquer Array Methods neles, você verá quando chegar à parte do loop.
node : Vamos continuar usando a variável children , então é assim que você definiria as propriedades dos children :
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . className = 'containerChild' ;
children [ i ] . textContent = 'This is some text' ;
} Veja como você faria isso com NodeList.js :
$$ ( '.child' ) . className = 'containerChild' ;
$$ ( '.child' ) . textContent = 'This is some text' ; node : Ainda usando a variável children :
Vamos adicionar um ouvinte de eventos a cada nó, embora event delegation seja melhor, mas para fins deste exemplo:
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ;
} Veja como você faria isso com NodeList.js :
$$ ( '.child' ) . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ; Tão legal, certo? Você pode usar qualquer Native DOM method :
Vamos definir alguns atributos:
$$ ( '.child' ) . setAttribute ( 'class' , 'child div' ) ;
// For setting the class you could just do:
$$ ( '.child' ) . className = 'child div' ;Clicando nos elementos:
$$ ( '.child' ) . click ( ) ;Removendo os elementos:
$$ ( '.child' ) . remove ( ) ; Acho que você está entendendo: qualquer Native DOM Method que cada Node/Element herda, você pode simplesmente chamar no NodeList e ele será chamado em cada elemento.
BTW: Todos os métodos DOM que normalmente retornariam undefined quando chamados em um único Node retornarão o mesmo NodeList para permitir o encadeamento de métodos. Como setAttribute() .
Usando um loop for e ES6 for-of :
Removeremos apenas os nós do DOM como exemplos:
let nodes = $$ ( '.child' ) ;
for ( let i = 0 , l = nodes . length ; i < l ; i ++ ) {
nodes [ i ] . remove ( ) ;
}
for ( let node of nodes ) {
node . remove ( ) ;
} Usando forEach :
// Removes all Nodes and returns same the NodeList to allow method chaining
$$ ( '.child' ) . forEach ( function ( node ) {
node . remove ( ) ;
} ) ;
// But Just do:
$$ ( '.child' ) . remove ( ) ;Percorrendo as propriedades:
// 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 ) ; Mapear é fácil, basta obter a propriedade como faria em um único nó
// 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' ) ;
} ) ; Não consegui pensar em um exemplo melhor para usar Reduzir em um NodeList (mas é possível)
let unique = $$ ( 'div' ) . reduce ( function ( set , div ) {
set . add ( div . parentElement ) ;
return set ;
} , new Set ( ) ) ; Há também reduceRight()
Todos os métodos concat() a seguir retornam um novo NodeList concatenado (não afetando o NodeList em que concat() está sendo chamado)
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() é recursivo, então você pode passar um Array tão profundo quanto desejar.
Agora, se você passar qualquer coisa que não seja Node , NodeList , HTMLCollections , Array ou Deep Array of Arrays que contenha algo diferente de Node , NodeList , HTMLCollections , Array gerará um 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() recebe um argumento opcional de quantos Nodes para 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() também recebe um argumento opcional de quantos Nodes ser 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 ) ; Vamos substituir o primeiro elemento que seria #container por 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 ( ) ; Não coloquei um método join para NodeLists porque seria inútil nos nós reais:
// Returns "[object HTMLDivElement], [object HTMLDivElement] ..."
$$ ( '.child' ) . join ( ) ;Portanto, você ainda pode usá-lo ao mapear propriedades:
// 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 ;
} ) ; Pode haver métodos DOM com o mesmo nome de Array.prototype no futuro, ou você pode apenas querer converter o NodeList em um Array , portanto, você pode usar como um Array nativo :
asArray $$ ( 'body' ) . asArray ; // returns Array
$$ ( 'body' ) . asArray . forEach ( function ( ) { ... } ) ; // uses native Array method therefore you cannot chain Ok, agora que tal lidar com elementos que possuem propriedades únicas. Assim como HTMLAnchorElement(s) eles possuem a propriedade href que não é herdada de HTMLElement . Não há HTMLAnchorElements neste exemplo, mas veja como você lidará com isso.
// 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() também pode ser usado em um Array de propriedades:
// 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() definirá apenas as propriedades nos Nodes cujas propriedades não são indefinidas:
$$ ( 'div, a' ) . set ( 'href' , 'https://www.example.com/' ) ; href será definido apenas nos elementos <a> e não nos <div> s
set() também pode ser usado em um Array de propriedades:
// Sets each element's color to red and returns the Array of styles back
$$ ( '.child' ) . style . set ( 'color' , 'red' ) ;Você também pode definir várias propriedades:
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) ;O mesmo com propriedades mapeadas:
$$ ( '.child' ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ;Lembre-se de que você pode encadear:
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ; Existem métodos que são exclusivos para determinados elementos. É assim que você chamaria esses métodos:
$$ ( 'video' ) . call ( 'pause' ) ;Ou você pode simplesmente percorrer os elementos e chamar os métodos
E quanto à passagem de argumentos:
// Returns Array of `CanvasRenderingContext2D`
$$ ( 'canvas' ) . call ( 'getContext' , '2d' ) ; Se o método chamado em qualquer um dos elementos retornar algo, um Array desses itens retornados seria retornado de call() caso contrário, NodeList será retornado para permitir o encadeamento de métodos.
O método item(index) nativo do navegador faz o mesmo que NodeList[index] mas no meu ele retorna esse Node como my NodeList (se você conhece jQuery é o mesmo que o método eq() do jQuery)
// returns the <html> element
$$ ( 'html, body' ) [ 0 ] ;
// returns my NodeList [<html>]
$$ ( 'html, body' ) . item ( 0 ) ; Isso é para que você possa continuar usando as mesmas propriedades/métodos do meu NodeList, em vez de ter que slice o único Node
owner : Tudo o que a propriedade do proprietário faz é devolver o NodeList do qual a propriedade foi mapeada:
var elms = $$ ( '.child' ) ;
elms . style . owner === elms ; // trueEntão eu posso fazer todos os tipos de coisas:
Lembre-se de que style de mapeamento retorna um Array de CSSStyleDeclarations
$$ ( '.child' ) . style ; Isso retornará o NodeList do qual style foi mapeado:
var childs = $$ ( '.child' ) ;
childs . style . owner === childs ; // true Se você conhece jQuery é igual à propriedade 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
} ) ;
}| Navegador | Versão |
|---|---|
| FireFox | 6+ |
| Safári | 5.0.5+ |
| Cromo | 6+ |
| Ou seja | 9+ |
| Ópera | 11+ |
Atenção: Você tem que perceber que minha biblioteca depende do navegador que está executando (o que é incrível, então ela é atualizada automaticamente quando o navegador atualiza o DOM com novas propriedades/métodos) ou seja: digamos que a propriedade hidden não existe no navegador API DOM que você não pode fazer: $$('.child').hidden = true;