NodeList.js
делает использование Native DOM API для Array
Nodes
таким же простым, как jQuery
с преимуществами его чрезвычайно малого размера (около 4 КБ) , а также браузера в качестве зависимости (это самая интересная часть) .
Первое, что вы заметите, это то, что я использую $$
. Причина, по которой я выбрал это для выбора DOM Nodes
, заключается в том, что если вы откроете свои инструменты разработчика и введете следующее:
$$ ( 'div' ) ; // Will return a NodeList
NodeList.js
: HTML
мы будем манипулировать далее: < 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
: Каждое из следующих значений возвращает Array of Nodes
(он же мой NodeList
, а не собственный NodeList
браузера)
// Method 1
$$ ( '#container div' ) ;
// Method 2
$$ ( '#container' ) . children ;
// Method 3
$$ ( 'div div' ) ;
Если вы передаете строку запроса, есть второй аргумент, который вы можете передать в качестве области действия:
let container = document . getElementById ( 'container' ) ;
$$ ( 'div' , container ) ;
Что будет эквивалентно:
// Just this doesn't return my NodeList, but the browser's NodeList
container . querySelectorAll ( 'div' ) ;
Вы можете передавать узлы в качестве аргументов:
$$(document, document.body); // returns NodeList
Вы также можете передать 1 Array
узлов, NodeList
или HTMLCollection
Не будет сведено, чтобы сгладить, используйте concat()
:
$$([document, document.body]); // returns NodeList
Node
:Как вы обычно это делаете:
let children = document . getElementsByClassName ( 'child' ) ;
Теперь вы получите свойства дочерних элементов #container
:
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . id ; // ''
children [ i ] . nodeName ; // 'DIV'
children [ i ] . className ; // 'child'
}
Вот как это можно сделать с помощью nodeList.js
:
$$ ( '.child' ) . id ; // ['', '' ... x10]
$$ ( '.child' ) . nodeName ; // ['DIV', 'DIV' ... x10]
$$ ( '.child' ) . className ; // ['child', 'child' ... x10]
Поэтому вы будете читать каждое свойство так же, как если бы вы читали один Node
:)
Обратите внимание, как он возвращает Array
значений свойств. Это означает, что вы можете выбирать их по index
и использовать к ним любые Array Methods
, вы увидите, когда доберетесь до части цикла.
node
: Давайте продолжим использовать переменную children
, вот как вы можете установить свойства для children
:
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . className = 'containerChild' ;
children [ i ] . textContent = 'This is some text' ;
}
Вот как это можно сделать с помощью NodeList.js
:
$$ ( '.child' ) . className = 'containerChild' ;
$$ ( '.child' ) . textContent = 'This is some text' ;
node
: Все еще используя переменную children
:
Давайте добавим прослушиватель событий на каждый узел, хотя event delegation
было бы лучше, но ради этого примера:
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
children [ i ] . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ;
}
Вот как это можно сделать с помощью NodeList.js
:
$$ ( '.child' ) . addEventListener ( 'click' , function ( ) {
console . log ( this , 'was clicked' ) ;
} ) ;
Так круто, правда? Вы можете использовать любой Native DOM method
:
Давайте установим некоторые атрибуты:
$$ ( '.child' ) . setAttribute ( 'class' , 'child div' ) ;
// For setting the class you could just do:
$$ ( '.child' ) . className = 'child div' ;
Щелкаем по элементам:
$$ ( '.child' ) . click ( ) ;
Удаление элементов:
$$ ( '.child' ) . remove ( ) ;
Я думаю, вы поняли суть: любой Native DOM Method
, который наследует каждый Node/Element
, вы можете просто вызвать NodeList
, и он будет вызываться для каждого элемента.
Кстати: все методы DOM
, которые обычно возвращают undefined
при вызове на одном Node
возвращают тот же NodeList
обратно, чтобы разрешить цепочку методов. Например, setAttribute()
.
Использование цикла for и for-of
ES6
:
В качестве примера мы просто удалим узлы из DOM
:
let nodes = $$ ( '.child' ) ;
for ( let i = 0 , l = nodes . length ; i < l ; i ++ ) {
nodes [ i ] . remove ( ) ;
}
for ( let node of nodes ) {
node . remove ( ) ;
}
Использование forEach
:
// Removes all Nodes and returns same the NodeList to allow method chaining
$$ ( '.child' ) . forEach ( function ( node ) {
node . remove ( ) ;
} ) ;
// But Just do:
$$ ( '.child' ) . remove ( ) ;
Перебирая свойства:
// 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 ) ;
Сопоставление легко, просто получите свойство так же, как и на одном узле.
// 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' ) ;
} ) ;
Я не мог придумать лучшего примера использования сокращения в NodeList (но это возможно).
let unique = $$ ( 'div' ) . reduce ( function ( set , div ) {
set . add ( div . parentElement ) ;
return set ;
} , new Set ( ) ) ;
Также есть reduceRight()
Следующие методы concat()
возвращают новый объединенный NodeList
(не влияет на NodeList
который вызывается concat()
)
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()
является рекурсивным, поэтому вы можете передать Array
любой глубины.
Теперь, если вы передадите что-либо, кроме Node
, NodeList
, HTMLCollections
, Array
или глубокого Array of Arrays
, содержащее что-то отличное от Node
, NodeList
, HTMLCollections
, Array
выдаст 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()
принимает необязательный аргумент, указывающий, сколько 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()
также принимает необязательный аргумент, указывающий, сколько Nodes
нужно переместить.
// 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 ) ;
Давайте заменим первый элемент #container на 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 ( ) ;
Я не добавил метод join
для NodeLists
потому что на реальных узлах он был бы бесполезен:
// Returns "[object HTMLDivElement], [object HTMLDivElement] ..."
$$ ( '.child' ) . join ( ) ;
Поэтому вы все равно можете использовать его при сопоставлении свойств:
// 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 ;
} ) ;
В будущем могут появиться методы DOM
с тем же именем, что и у Array.prototype
, или вы можете просто преобразовать NodeList
в Array
поэтому вы можете использовать его как собственный Array
:
asArray
$$ ( 'body' ) . asArray ; // returns Array
$$ ( 'body' ) . asArray . forEach ( function ( ) { ... } ) ; // uses native Array method therefore you cannot chain
Хорошо, а теперь как насчет работы с элементами, имеющими уникальные свойства? Как и HTMLAnchorElement(s)
они имеют свойство href
, которое не унаследовано от HTMLElement
. В этом примере нет HTMLAnchorElements
, но вот как с этим справиться.
// 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()
также можно использовать для Array
свойств:
// 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()
установит свойства только на Nodes
, свойства которых не определены:
$$ ( 'div, a' ) . set ( 'href' , 'https://www.example.com/' ) ;
href
будет установлен только для элементов <a>
, а не для <div>
set()
также можно использовать для Array
свойств:
// Sets each element's color to red and returns the Array of styles back
$$ ( '.child' ) . style . set ( 'color' , 'red' ) ;
Вы также можете установить несколько свойств:
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) ;
То же самое с сопоставленными свойствами:
$$ ( '.child' ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ;
Помните, что вы можете связать:
$$ ( '.child' ) . set ( {
textContent : 'Hello World' ,
className : 'class1 class2'
} ) . style . set ( {
color : 'red' ,
background : 'black'
} ) ;
Существуют методы, уникальные для определенных элементов. Вот как вы могли бы назвать эти методы:
$$ ( 'video' ) . call ( 'pause' ) ;
Или вы можете просто перебрать элементы и вызвать методы
А как насчет передачи аргументов:
// Returns Array of `CanvasRenderingContext2D`
$$ ( 'canvas' ) . call ( 'getContext' , '2d' ) ;
Если метод, вызванный для любого из элементов, возвращает что-то, из call()
будет возвращен Array
этих возвращенных элементов, в противном случае будет возвращен NodeList
, чтобы разрешить цепочку методов.
Собственный метод item(index)
браузера делает то же самое, что и NodeList[index]
но в моем случае он возвращает этот Node
как мой NodeList
(если вы знаете jQuery
это то же самое, что метод jQuery eq()
)
// returns the <html> element
$$ ( 'html, body' ) [ 0 ] ;
// returns my NodeList [<html>]
$$ ( 'html, body' ) . item ( 0 ) ;
Это сделано для того, чтобы вы могли продолжать использовать те же свойства/методы моего NodeList, вместо того, чтобы slice
один Node
owner
: Все, что делает свойство владельца, — это возвращает вам NodeList
, из которого было сопоставлено свойство:
var elms = $$ ( '.child' ) ;
elms . style . owner === elms ; // true
Итак, я могу делать все что угодно:
Помните, что style
отображения возвращает Array
CSSStyleDeclarations
$$ ( '.child' ) . style ;
Это вернет вам NodeList
, из которого был сопоставлен style
:
var childs = $$ ( '.child' ) ;
childs . style . owner === childs ; // true
Если вы знаете jQuery
это то же самое, что и его свойство 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
} ) ;
}
Браузер | Версия |
---|---|
ФаерФокс | 6+ |
Сафари | 5.0.5+ |
Хром | 6+ |
ИЕ | 9+ |
Опера | 11+ |
Внимание: вы должны понимать, что моя библиотека зависит от браузера, в котором она работает (и это здорово, поэтому она автоматически обновляется, когда браузер обновляет DOM
новыми свойствами/методами). Это означает: допустим, hidden
свойство не существует в браузере. DOM
API вы не можете: $$('.child').hidden = true;