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


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 相关文章推荐
js仿百度贴吧验证码特效实例代码
Jan 16 Javascript
JavaScript制作的可折叠弹出式菜单示例
Apr 04 Javascript
jQuery选择器源码解读(二):select方法
Mar 31 Javascript
vue2.0中vue-cli实现全选、单选计算总价格的实例代码
Jul 18 Javascript
JS实现的判断方法、变量是否存在功能示例
Mar 28 Javascript
vue router 跳转后回到顶部的实例
Aug 31 Javascript
JavaScript动态创建二维数组的方法示例
Feb 01 Javascript
使用vue开发移动端管理后台的注意事项
Mar 07 Javascript
layUI实现列表查询功能
Jul 27 Javascript
微信小程序分包加载代码实现方法详解
Sep 23 Javascript
mapboxgl区划标签避让不遮盖实现的代码详解
Jul 01 Javascript
Vue基本指令实例图文讲解
Feb 25 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
Zend Studio 无法启动的问题解决方法
2008/12/04 PHP
在IIS7.0下面配置PHP 5.3.2运行环境的方法
2010/04/13 PHP
php UBB 解析实现代码
2011/11/27 PHP
PHP批量检测并去除文件BOM头代码实例
2014/05/08 PHP
php实现批量压缩图片文件大小的脚本
2014/07/04 PHP
php格式化电话号码的方法
2015/04/24 PHP
php获取微信基础接口凭证Access_token
2018/08/23 PHP
JavaScript中this关键字使用方法详解
2007/03/08 Javascript
根据经纬度计算地球上两点之间的距离js实现代码
2013/03/05 Javascript
get(0).tagName获得作用标签示例代码
2014/10/08 Javascript
javascript实现动态改变层大小的方法
2015/05/14 Javascript
js精美的幻灯片画集特效代码分享
2015/08/29 Javascript
解决bootstrap导航栏navbar在IE8上存在缺陷的方法
2016/07/01 Javascript
AngularJS基础 ng-selected 指令简单示例
2016/08/03 Javascript
js仿百度音乐全选操作
2017/01/13 Javascript
Angular4表单验证代码详解
2017/09/03 Javascript
JS计算输出100元钱买100只鸡问题的解决方法
2018/01/04 Javascript
vue 使用Jade模板写html,stylus写css的方法
2018/02/23 Javascript
微信小程序五子棋游戏的悔棋实现方法【附demo源码下载】
2019/02/20 Javascript
详解服务端预渲染之Nuxt(介绍篇)
2019/04/07 Javascript
layui 上传文件_批量导入数据UI的方法
2019/09/23 Javascript
JavaScript中的函数申明、函数表达式、箭头函数
2019/12/06 Javascript
vue使用原生swiper代码实例
2020/02/05 Javascript
用Nodejs实现在终端中炒股的实现
2020/10/18 NodeJs
跟老齐学Python之从if开始语句的征程
2014/09/14 Python
python下实现二叉堆以及堆排序的示例
2017/09/29 Python
Python文件的读写和异常代码示例
2017/10/31 Python
python读写配置文件操作示例
2019/07/03 Python
Python pandas如何向excel添加数据
2020/05/22 Python
Python常用外部指令执行代码实例
2020/11/05 Python
Python爬虫之Selenium多窗口切换的实现
2020/12/04 Python
美国Lolё官网:购买大胆而美丽的女性运动服装
2017/05/22 全球购物
PHP如何防止SQL注入
2014/05/03 面试题
大学生优秀的自我评价分享
2013/10/22 职场文书
入股协议书范本
2014/04/14 职场文书
学生党员检讨书范文
2014/12/27 职场文书