jQuery的遍历结构设计之遍历同胞
前言:光看不行,需要动手操作!
一、本文实现的 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 从数组中去掉
(完)