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