يجعل NodeList.js
استخدام واجهات برمجة تطبيقات DOM الأصلية على Array
من Nodes
أمرًا سهلاً مثل jQuery
مع فوائد كونه صغيرًا للغاية عند حوالي 4k مصغرًا ، والمتصفح باعتباره تبعية (وهذا هو الجزء الأكثر إثارة للاهتمام) .
أول شيء ستلاحظه هو أنني أستخدم $$
، وسبب اختياري لهذا الخيار لاختيار 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
(AKA my 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
يمكنك أيضًا تمرير 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 و ES6
for-of
:
سنقوم فقط بإزالة العقد من 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' ) ;
} ) ;
لا يمكنني التفكير في مثال أفضل لاستخدام "Reduce" في 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
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 ) ;
لنستبدل العنصر الأول الذي سيكون #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' ) ;
إذا قامت الطريقة التي تم استدعاؤها على أي من العناصر بإرجاع شيء ما، فسيتم إرجاع Array
من تلك العناصر التي تم إرجاعها من call()
وإلا سيتم إرجاع NodeList
للسماح بتسلسل الطريقة.
تعمل طريقة item(index)
الأصلية للمتصفح بنفس طريقة NodeList[index]
ولكنها تُرجع تلك Node
باعتبارها NodeList
الخاصة بي (إذا كنت تعرف jQuery
فهي نفس طريقة eq()
الخاصة بـ jQuery)
// 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
التي لا يمكنك تنفيذها: $$('.child').hidden = true;