前言:光看不行,需要動手操作!
一、本文實現的 jQuery 的同胞介面及作用如下
介面:$(selector).nextAll()
作用:向後遍歷同胞,返回 selector
之後的所有同級元素
介面:$(selector).prevAll()
作用:向前遍歷同胞,返回 selector
之前的所有同級元素
介面:$(selector).nextUntil(otherSelector)
作用: 向後遍歷同胞,返回在 selector
和 otherSelector
之間的所有同級元素
介面:$(selector).prevUntil(otherSelector)
作用: 向前遍歷同胞,返回在 otherSelector
和 selector
之間的所有同級元素
介面:$(selector).next()
作用: 返回 selector
的後一個同級元素
介面:$(selector).prev()
作用:返回 selector
的前一個同級元素
介面:$(selector).siblings()
作用:返回 selector
的所有同胞元素(共享一個父元素,且不包括自己)
將這些介面封裝在 jQuery 的迭代器中 ↓
二、迭代器
迭代器可以理解為一個遍歷方法,
該方法的第一個引數是一個 object,該物件的每個屬性都是一個 function;
該方法的第二個引數是一個 callback,該回撥函式能夠按順序處理 object 的每個 function,並且不暴露 object 的內部。
- jQuery 遍歷同胞的迭代器程式碼:
let ajQuery = {}
jQuery.each({
// nextAll() 方法返回被選元素之後的所有同級元素
// 同級元素是共享相同父元素的元素
//詳細請看:http://www.runoob.com/jquery/traversing-nextall.html
//nextAll的本質即利用 elem.nextSibling,抓取element節點,向後遞迴直到elem=null
nextAll:function (elem) {
return dir(elem, "nextSibling")
},
//prevAll() 方法返回被選元素之前的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-prevall.html
//prevAll的本質即利用 elem.previousSibling,抓取element節點,向前遞迴直到elem=null
prevAll:function (elem) {
return dir(elem, "previousSibling")
},
//返回在類名為 "item-1" 和 "item-4" 的兩個 <li> 元素之間的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-nextuntil.html
//nextUntil的本質即利用 elem.nextSibling,抓取element節點,
//向後遞迴直到elem.nodeName.toLowerCase()===until||elem.className === until
nextUntil:function (elem, until) {
return dir(elem, "nextSibling", until)
},
//返回在類名為 "item-4" 和 "item-1" 的兩個 <li> 元素之間的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-prevuntil.html
//prevUntil的本質即利用 elem.previousSibling,抓取element節點,
//向前遞迴直到elem.nodeName.toLowerCase()===until||elem.className === until
prevUntil: function (elem, until) {
return dir(elem, "previousSibling", until)
},
//next:返回被選元素的 後一個同級元素
next: function (elem) {
return sibling(elem, "nextSibling");
},
//prev:返回被選元素的 前一個同級元素
prev: function (elem) {
return sibling(elem, "previousSibling");
},
//siblings:返回被選元素的 所有同胞元素(共享一個父元素,且不包括自己)
siblings: function (elem) {
return dir(elem, "siblings")
}
},
function(key, value) {
ajQuery[key] = function(elem, until) {
return value(elem, until);
}
})
複製程式碼
三、使用 dir() 和 sibling() 方法來封裝 遍歷同胞 的方法
- dir() 封裝除
$().next()
和$().pre()
以外的 遍歷同胞的方法:
function dir(elem, dir, until) {
let matched = []
//是否有另一目標節點
let hasUntil = until !== undefined
let sibElem
let isSibling=false
//$().siblings()的實現有兩種方法
//第一種是先 prevAll 向前遍歷目標元素的同胞元素,再 nextAll向後遍歷目標元素的同胞元素
//第二種是先找到父元素的第一個元素,再 nextAll向後遍歷同胞元素,最後將 目標元素從陣列中去掉
//這裡採用的是第二種方式
if(dir==='siblings'){
sibElem=elem
isSibling=true
elem=elem.parentNode.firstElementChild
dir='nextSibling'
matched.push(elem)
}
//nextAll:一直nextSibling,直到elem=null,退出迴圈
while ((elem = elem[dir])&&elem.nodeType !== 9) {
if (elem.nodeType === 1) {
//nextUntil:true
if (hasUntil) {
console.log(elem.nodeName.toLowerCase(),elem.className,'className44')
if (elem.nodeName.toLowerCase() === until || elem.className === until) {
console.log(until,'until46')
break
}
}
console.log(elem,'elem50')
matched.push(elem)
}
}
//迴圈完後,去除目標元素
if(isSibling){
console.log(sibElem,matched.indexOf(sibElem),'sibElem66')
matched.splice(matched.indexOf(sibElem),1)
}
return matched
}
複製程式碼
- sibling() 封裝
$().next()
和$().pre()
方法:
function sibling(elem, dir) {
//過濾掉不是element型別的元素
while ((elem = elem[dir]) && elem.nodeType !== 1) { }
return elem
}
複製程式碼
四、完整程式碼及例項
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery的遍歷結構設計之遍歷同胞</title>
</head>
<body>
<script src="jQuery.js"></script>
<button id="test1">模擬遍歷同胞</button>
<button id="test2">jQuery遍歷同胞</button>
<ul class="level-1">
<li class="item-i">I</li>
<!--目標節點-->
<li class="item-ii">II
<ul class="level-2">
<li class="item-a">A</li>
<li class="item-b">B
<ul class="level-3">
<li class="item-1">1</li>
<li class="item-2">2</li>
<li class="item-3">3</li>
<li class="item-4">4</li>
</ul>
</li>
<li class="item-c">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
<script type="text/javascript">
function dir(elem, dir, until) {
let matched = []
let truncate = until !== undefined
let sibElem
let isSibling=false
//遍歷同胞元素有兩種方法
//第一種是先 prevAll 向前遍歷目標元素的同胞元素,再 nextAll向後遍歷目標元素的同胞元素
//第二種是先找到父元素的第一個元素,再 nextAll向後遍歷同胞元素,最後將 目標元素從陣列中去掉
//這裡採用的是第二種方式
if(dir==='siblings'){
sibElem=elem
isSibling=true
elem=elem.parentNode.firstElementChild
dir='nextSibling'
matched.push(elem)
}
//nextAll:一直nextSibling,直到elem=null,退出迴圈
while ((elem = elem[dir])&&elem.nodeType !== 9) {
if (elem.nodeType === 1) {
//nextUntil:true
if (truncate) {
console.log(elem.nodeName.toLowerCase(),elem.className,'className44')
if (elem.nodeName.toLowerCase() === until || elem.className === until) {
console.log(until,'until46')
break
}
}
console.log(elem,'elem50')
matched.push(elem)
}
}
//迴圈完後,去除目標元素
if(isSibling){
console.log(sibElem,matched.indexOf(sibElem),'sibElem66')
matched.splice(matched.indexOf(sibElem),1)
}
return matched
}
function sibling(elem, dir) {
//過濾掉不是element型別的元素
while ((elem = elem[dir]) && elem.nodeType !== 1) { }
return elem
}
let ajQuery = {}
jQuery.each({
// nextAll() 方法返回被選元素之後的所有同級元素
// 同級元素是共享相同父元素的元素
//詳細請看:http://www.runoob.com/jquery/traversing-nextall.html
//nextAll的本質即利用 elem.nextSibling,抓取element節點,向後遞迴直到elem=null
nextAll:function (elem) {
return dir(elem, "nextSibling")
},
//prevAll() 方法返回被選元素之前的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-prevall.html
//prevAll的本質即利用 elem.previousSibling,抓取element節點,向前遞迴直到elem=null
prevAll:function (elem) {
return dir(elem, "previousSibling")
},
//返回在類名為 "item-1" 和 "item-4" 的兩個 <li> 元素之間的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-nextuntil.html
//nextUntil的本質即利用 elem.nextSibling,抓取element節點,
//向後遞迴直到elem.nodeName.toLowerCase()===until||elem.className === until
nextUntil:function (elem, until) {
return dir(elem, "nextSibling", until)
},
//返回在類名為 "item-4" 和 "item-1" 的兩個 <li> 元素之間的所有同級元素
//詳細請看:http://www.runoob.com/jquery/traversing-prevuntil.html
//prevUntil的本質即利用 elem.previousSibling,抓取element節點,
//向前遞迴直到elem.nodeName.toLowerCase()===until||elem.className === until
prevUntil: function (elem, until) {
return dir(elem, "previousSibling", until)
},
//next:返回被選元素的 後一個同級元素
next: function (elem) {
return sibling(elem, "nextSibling");
},
//prev:返回被選元素的 前一個同級元素
prev: function (elem) {
return sibling(elem, "previousSibling");
},
//siblings:返回被選元素的 所有同胞元素(共享一個父元素,且不包括自己)
siblings: function (elem) {
return dir(elem, "siblings")
}
},
function(key, value) {
ajQuery[key] = function(elem, until) {
return value(elem, until);
}
})
$("#test1").click(function(){
// let item = document.querySelectorAll('li.item-ii')[0]
// let item = document.querySelectorAll('li.item-1')[0]
let item = document.querySelectorAll('li.item-2')[0]
//#text 3
//nodeType=3,而不是1,所以不符合要求
// console.log(item.nextSibling,item.nextSibling.nodeType)
// console.log(item.nextSibling.nextSibling,item.nextSibling.nextSibling.nodeType)
// console.log(item.nextSibling.nextSibling.nextSibling,item.nextSibling.nextSibling.nextSibling.nodeType)
// //null
// console.log(item.nextSibling.nextSibling.nextSibling.nextSibling)
// console.log(ajQuery.nextAll(item))
// console.log(ajQuery.nextAll(item)[0].className)
// console.log(ajQuery.prevAll(item)[0].className)
// console.log(ajQuery.nextUntil(item, 'item-4'),'item107')
// console.log(ajQuery.nextUntil(item, 'item-4')[0].className,'item108')
// console.log(ajQuery.prevUntil(item, 'item-2')[0].className)
//
// console.log(prev(item))
// console.log(next(item))
// Siblings item.parentNode.firstElementChild
console.log(ajQuery.siblings(item,'siblings'),'siblings151')
})
$("#test2").click(function(){
let $item = $('li.item-2')
console.log($item.nextAll()[0].className)
console.log($item.prevAll()[0].className)
console.log($item.nextUntil('item-4'))
console.log($item.nextUntil('item-4')[0].className)
console.log($item.prevUntil('item-2')[0].className)
console.log($item.prev())
console.log($item.next())
})
</script>
</body>
</html>
複製程式碼
五、總結
注: element 表示 jQuery物件selector
的原生 DOM 節點
介面:$(selector).nextAll()
本質: 利用 element=element.nextSibling,抓取 element 的同胞節點,並向後遞迴直到 element=null,此時返回 selector 向後遍歷的所有同胞節點
介面:$(selector).prevAll()
本質: 利用 element=element.previousSibling,抓取 element 的同胞節點,並向前遞迴直到 element=null,此時返回 selector 向前遍歷的所有同胞節點
介面:$(selector).nextUntil(otherSelector)
本質: 利用 element=element.nextSibling,抓取 element 的同胞節點,並向後遞迴直到 elem.nodeName.toLowerCase()===otherSelector || elem.className === otherSelector
,此時返回 selector 向後遍歷到 otherSelector 之間的所有同胞節點
介面:$(selector).prevUntil(otherSelector)
本質: 利用 element=element.previousSibling,抓取 element 的同胞節點,並向前遞迴直到 elem.nodeName.toLowerCase()===otherSelector || elem.className === otherSelector
,此時返回 selector 向前遍歷到 otherSelector 之間的所有同胞節點
介面:$(selector).next()
本質: 利用 element=element.nextSibling 和 elem.nodeType !== 1
,過濾並抓取 元素型別 的後一個同胞節點
介面:$(selector).prev()
本質: 利用 element=element.previousSibling 和 elem.nodeType !== 1
,過濾並抓取 元素型別 的前一個同胞節點
介面:$(selector).siblings()
本質: 先找到父元素的第一個元素,再 nextAll() 向後遍歷同胞元素,最後將 selector 從陣列中去掉
(完)