前言:光看不行,需要动手操作!
一、本文实现的 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 从数组中去掉
(完)
网友评论