高效的获取当前元素是父元素的第几个子元素


Posted in Javascript onOctober 15, 2013

例如处理事件的时候,有时候需要知道当前点击的是第几个子节点,而HTML DOM本身并没有直接提供相应的属性,需要自己来计算。

从一个索引序号,很容易得到该索引对应的子节点或者子元素,直接用parentNode.childNodes[index] 或 parentNode.children[index] 就行。

但反过来,已知一个节点或元素对象,要知道它的索引序号则没有那么直接了。

一些特殊的元素,HTML DOM有对应的属性表示其索引序号,主要是表格的TD 和 TR 元素。

表格单元格TD元素有 cellIndex 属性。

表格行TR元素有rowIndex属性。

如果你的处理目标刚好就是表格,则优先使用这两个属性。

但一般的节点或元素并没有 childNodeIndex 或者 childElementIndex 之类的属性。

解决方案主要分为两类:

一、预先计算并缓存节点的索引号(可以存在节点属性或者js变量中)。

二、实时计算,需要遍历部分节点。

应用中,可根据不同的实际情况,选用上述两类方案之一。

适用方案一的情形:

当DOM结构不会变化,并且需要频繁的获取个别节点的索引,可采用方案一。

优点是后续读取快,缺点是初始化需要开销,DOM结构变化后需要重新初始化。

适用方案二的情形:

DOM结构可能会变化,并且不是特别频繁的获取个别节点的索引,可采用方案二。

优点是不受DOM结构变化的影响,不会污染DOM结构,没有初始化开销。缺点是不适合高频率调用。

一般而言,采用方案二是更好的,因为通常DOM树规模是比较有限的,一轮的循环并不会导致显著降低整体性能,而其优点则是显著的。

对于IE浏览器,则有更直接的方法。

从IE4到IE11,都有sourceIndex属性,这个属性表示了元素在DOM树的顺序,比较元素和父元素的sourceIndex的差值就很容易知道元素是第几个子元素了。

我写了一段函数来区分处理,在IE下采用sourceIndex高效判断,非IE则采用一般遍历。

function getChildrenIndex(ele){ 
//IE is simplest and fastest 
if(ele.sourceIndex){ 
return ele.sourceIndex - ele.parentNode.sourceIndex - 1; 
} 
//other browsers 
var i=0; 
while(ele = ele.previousElementSibling){ 
i++; 
} 
return i; 
}

上面的函数只是计算元素Element,也就是nodeType为1的节点,文本节点、注释节点等将不被统计。如果需要计算所有节点在内,则不能适用sourceIndex,因为该属性只针对Element. previousElementSibling也要相应的改为previousSibling. 那就要写成如下的函数了:
function getNodeIndex(node){ 
var i=0; 
while(ele = ele.previousSibling){ 
i++; 
} 
return i; 
}

后记:在非IE下,有 compareDocumentPosition 方法用于比较节点的位置关系,但经过测试该方法的性能非常差,其内部的实现机制肯定不是像IE那样缓存了资源索引号的,如果这个方法极高效,那就可采用二分法进行计算,从而提高效率,但目前还不可能。

最后的总结:

对于表格TD和TR元素优先使用cellIndex和rowIndex属性。

对于IE优先使用sourceIndex属性。

其它情形使用previousElementSibling 或 previousSibling 进行遍历。

compareDocumentPosition 方法的性能非常差。

Javascript 相关文章推荐
JavaScript匿名函数用法分析
Feb 13 Javascript
JavaScript实现简单的日历效果
Sep 25 Javascript
pc加载更多功能和移动端下拉刷新加载数据
Nov 07 Javascript
微信小程序 删除项目工程实现步骤
Nov 10 Javascript
jQuery Validate 数组 全部验证问题
Jan 12 Javascript
基于BootStrap的前端分页带省略号和上下页效果
May 18 Javascript
在vue中获取dom元素内容的方法
Jul 10 Javascript
Angular(5.2->6.1)升级小结
Dec 27 Javascript
JS实现的冒泡排序,快速排序,插入排序算法示例
Mar 02 Javascript
详解javascript中的Error对象
Apr 25 Javascript
浅探express路由和中间件的实现
Sep 30 Javascript
JavaScript中EventBus实现对象之间通信
Oct 18 Javascript
JS 实现点击a标签的时候让其背景更换
Oct 15 #Javascript
JS操作Cookies的小例子
Oct 15 #Javascript
如何在父窗口中得知window.open()出的子窗口关闭事件
Oct 15 #Javascript
JavaScript中prototype为对象添加属性的误区介绍
Oct 15 #Javascript
JS格式化数字保留两位小数点示例代码
Oct 15 #Javascript
js计算字符串长度包含的中文是utf8格式
Oct 15 #Javascript
Javascript中查找不以XX字符结尾的单词示例代码
Oct 15 #Javascript
You might like
第一个无线电台是由谁发明的
2021/03/01 无线电
测试php函数的方法
2013/11/13 PHP
php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比
2015/04/14 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
2017/11/16 PHP
PHP array_reduce()函数的应用解析
2018/10/28 PHP
PHP strripos函数用法总结
2019/02/11 PHP
javascript 中对象的继承〔转贴〕
2007/01/22 Javascript
jquery插件lazyload.js延迟加载图片的使用方法
2014/02/19 Javascript
防止按钮在短时间内被多次点击的方法
2014/03/10 Javascript
IE7浏览器窗口大小改变事件执行多次bug及IE6/IE7/IE8下resize问题
2015/08/21 Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
2016/01/19 Javascript
JS+CSS实现鼠标经过弹出一个DIV框完整实例(带缓冲动画渐变效果)
2016/03/25 Javascript
json实现添加、遍历与删除属性的方法
2016/06/17 Javascript
xmlplus组件设计系列之树(Tree)(9)
2017/05/02 Javascript
用angular实现多选按钮的全选与反选实例代码
2017/05/23 Javascript
基于AngularJS实现表单验证功能
2017/07/28 Javascript
JS获取子、父、兄节点方法小结
2017/08/14 Javascript
Vue学习笔记之表单输入控件绑定
2017/09/05 Javascript
react-native DatePicker日期选择组件的实现代码
2017/09/12 Javascript
jQuery实现模拟搜索引擎的智能提示功能简单示例
2019/01/27 jQuery
vue.js表单验证插件(vee-validate)的使用教程详解
2019/05/23 Javascript
详解基于Vue/React项目的移动端适配方案
2019/08/23 Javascript
javascript/jquery实现点击触发事件的方法分析
2019/11/11 jQuery
[01:01:41]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第二场 1月31日
2021/03/11 DOTA
使用Python对MySQL数据操作
2017/04/06 Python
Python基于csv模块实现读取与写入csv数据的方法
2018/01/18 Python
TensorFlow利用saver保存和提取参数的实例
2018/07/26 Python
python TKinter获取文本框内容的方法
2018/10/11 Python
为您搜罗全球潮流時尚品牌:HBX
2019/12/04 全球购物
初婚初育证明
2014/01/14 职场文书
运动会通讯稿100字
2014/01/31 职场文书
知识竞赛活动方案
2014/02/18 职场文书
2014年售票员工作总结
2014/11/19 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
2019年鼓励无偿献血倡议书
2019/09/17 职场文书
使用pandas或numpy处理数据中的空值(np.isnan()/pd.isnull())
2021/05/14 Python