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


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 相关文章推荐
自制基于jQuery的智能提示插件一枚
Feb 18 Javascript
简介JavaScript中的getUTCFullYear()方法的使用
Jun 10 Javascript
基于jQuery倒计时插件实现团购秒杀效果
May 13 Javascript
a标签跳转到指定div,jquery添加和移除class属性的实现方法
Oct 10 Javascript
Javascript for in的缺陷总结
Feb 03 Javascript
纯JS实现轮播图
Feb 22 Javascript
微信小程序 动态绑定事件并实现事件修改样式
Apr 13 Javascript
详解使用vuex进行菜单管理
Dec 21 Javascript
js时间戳转yyyy-MM-dd HH-mm-ss工具类详解
Apr 30 Javascript
JavaScript中的null和undefined用法解析
Sep 30 Javascript
JavaScript实现点击出现子菜单效果
Feb 08 Javascript
vue实现无缝轮播效果(跑马灯)
May 14 Vue.js
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
解析MySql与Java的时间类型
2013/06/22 PHP
php防注入及开发安全详细解析
2013/08/09 PHP
PHP小教程之实现链表
2014/06/09 PHP
在WordPress中使用wp-cron插件来设置定时任务
2015/12/10 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
2016/09/30 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
YII框架行为behaviors用法示例
2019/04/26 PHP
laravel自定义分页的实现案例offset()和limit()
2019/10/15 PHP
在页面上点击任一链接时触发一个事件的代码
2007/04/07 Javascript
javascript SpiderMonkey中的函数序列化如何进行
2012/12/05 Javascript
js 延迟加载 改变JS的位置加快网页加载速度
2012/12/11 Javascript
jQuery实现图片信息的浮动显示实例代码
2013/08/28 Javascript
jquery中获取元素里某一特定子元素的代码
2014/12/02 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
2015/05/09 Javascript
arguments对象验证函数的参数是否合法
2015/06/26 Javascript
js格式化输入框内金额、银行卡号
2016/02/01 Javascript
javascript html实现网页版日历代码
2016/03/08 Javascript
浅析Ajax语法
2016/12/05 Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
2017/04/01 Javascript
js防刷新的倒计时代码 js倒计时代码
2017/09/06 Javascript
VsCode插件整理(小结)
2017/09/14 Javascript
使用Vue.js和Flask来构建一个单页的App的示例
2018/03/21 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
2019/11/11 Javascript
Vue+Openlayers自定义轨迹动画
2020/09/24 Javascript
[58:11]守擂赛第二周擂主赛 DeMonsTer vs Leopard
2020/04/28 DOTA
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
Python简单计算文件夹大小的方法
2015/07/14 Python
pandas求两个表格不相交的集合方法
2018/12/08 Python
PythonWeb项目Django部署在Ubuntu18.04腾讯云主机上
2019/04/01 Python
Python后台开发Django的教程详解(启动)
2019/04/08 Python
在pyqt5中QLineEdit里面的内容回车发送的实例
2019/06/21 Python
Python利用scapy实现ARP欺骗的方法
2019/07/23 Python
历史学专业毕业生求职信
2013/09/27 职场文书
2014年艾滋病防治工作总结
2014/12/10 职场文书
复兴之路展览观后感
2015/06/02 职场文书
2015年小学远程教育工作总结
2015/07/28 职场文书