获取祖先元素
在设计选择器时遇到的,当我们使用后代选择器,要从上一次的结果集中获取它们所有后代,可能存在重复元素。虽然排除重复元素是非常简单的事,但我们能不能从一开始就防范其生产重复元素呢?答案是肯定。
假设上一次的结果集有三个元素a,b,c,如果其中两个存在包含关系,即是说A的parentNode或祖先是B,那么一定会出现重复的子集。既然如此,一开始,我们把A去掉,就没问题了。
看下面网页:
<!doctype html> <html dir= "ltr" lang= "zh-CN" > <head> <meta charset= "utf-8" /> <title>排除 重复元素 by 司徒正美</title> </head> <body id= "id10" > <p id= "id1" >一<span id= "id2" >二</span><span id= "id3" >二</span><span class = "bbb" >二</span></p> <p id= "id4" >一<span id= "id5" >二</span></p> <p title= "aaa" >一<span title= "aaa" >二</span></p> <div id= "id6" > <p id= "id7" ><strong id= "id8" >Strong<span id= "id9" >二</span></strong></p> </div> </body> </html> |
我们从它里面选择几个元素组成数组,模拟为选择器上一次选取的结果。
window.onload = function (){ var $ = function (id){ return document.getElementById(id); } var a = $( "id1" ); var b = $( "id2" ) var c = $( "id3" ) var d = $( "id4" ) var e = $( "id5" ) var f = $( "id6" ) var g = $( "id7" ) var h = $( "id8" ) var arr = [a,b,c,d,e,f,g,h]; } |
由于网页很简单,我们一眼就看得出,最终应该从中筛选出:a,d,f。
要实现这个目标,我们必须先对数组进行排序,让元素安排它们在页面上的位置从上到下,从左到右排序。这简单, 我们可以通过以下方法实现:
var sortOrder = function (){ if (!+ "\v1" ){ return function ( a, b ) { return a.sourceIndex - b.sourceIndex; } } else { return function (a,b){ a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; } } }(); |
我们还需要检测它们是否存在包含关系:
var contains = function (a,b){ if (!+ "\v1" ){ return a === b ? false : a.contains(b); } else { return !!(a.compareDocumentPosition(b) & 16) } } |
最后我们进行两两比较,把儿子与孙子都找出来,打上标记,没有标记的就是我们要找的祖先,那么从这些祖先获取的后代集合就一定没有重复元素了!
arr.sort(sortOrder); var getAncestor = function (array){ for ( var i = 0,n=array.length; i < n; i++) { for ( var j = n - 1; j > i; j--) { var a = array[i],b=array[j]; if (contains(a,b)) { b.no = 1; } else if (contains(b,a)) { a.no = 1 } } } var result = [],ri= 0 for ( var k=0;k<n;k++){ if (!array[k].no){ result[ri++] = array[k] } } return result; } var ancestor= getAncestor(arr) |
但是这样做有个致命的缺陷,就是只能筛选一次,下一次这个no私有属性将成为干扰因素,但移除私有属性费时费劲,因此建议使用uuid技术进行筛选。
arr.sort(sortOrder); var uuid = 0 var getAncestor = function (array){ var remove = {},uid ; for ( var i = 0,n=array.length; i < n; i++) { for ( var j = n - 1; j > i; j--) { //比如一共有五个元素,那么每趟为 var a = array[i],b=array[j]; if (contains(a,b)) { uid = b.uuid || (b.uuid = "dom-" +uuid++) ; remove[uid] = 1; } else if (contains(b,a)) { uid = a.uuid || (a.uuid = "dom-" +uuid++); remove[uid] = 1; } } } var result = [],ri= 0 for ( var k=0;k<n;k++){ if (!remove[array[k].uuid]){ result[ri++] = array[k] } } return result; } var ancestor = getAncestor(arr) for ( var i=0,n=ancestor.length;i<n;i++){ alert(ancestor[i].id) } |
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?