获取子节点索引

IT技术 javascript dom
2021-01-18 17:51:08

在直接的 javascript 中(即没有诸如 jQuery 等的扩展),有没有一种方法可以在不迭代和比较所有子节点的情况下确定其父节点内的子节点的索引?

例如,

var child = document.getElementById('my_element');
var parent = child.parentNode;
var childNodes = parent.childNodes;
var count = childNodes.length;
var child_index;
for (var i = 0; i < count; ++i) {
  if (child === childNodes[i]) {
    child_index = i;
    break;
  }
}

有没有更好的方法来确定孩子的指数?

6个回答

我已经喜欢用indexOf这个了。因为indexOfis onArray.prototypeparent.childrenis a NodeList,所以你必须使用call();它有点难看,但它是一个单行并使用任何 javascript 开发人员无论如何都应该熟悉的函数。

var child = document.getElementById('my_element');
var parent = child.parentNode;
// The equivalent of parent.children.indexOf(child)
var index = Array.prototype.indexOf.call(parent.children, child);
var index = [].indexOf.call(child.parentNode.children, child);
2021-03-27 17:51:08
为了评估[].indexOf引擎,必须创建一个数组实例来访问indexOf原型上的实现。实例本身未使用(它执行 GC,这不是泄漏,只是浪费周期)。Array.prototype.indexOf直接访问该实现而不分配匿名实例。几乎在所有情况下,这种差异都可以忽略不计,因此坦率地说,这可能不值得关心。
2021-03-31 17:51:08
小心 IE 中的错误!Internet Explorer 6、7 和 8 支持它,但错误地包含注释节点。来源” developer.mozilla.org/en-US/docs/Web/API/ParentNode/...
2021-04-04 17:51:08
Fwiw,[]每次运行该代码时using都会创建一个 Array 实例,与使用Array.prototype.
2021-04-07 17:51:08
@ScottMiles 我可以再解释一下你所说的吗?[]作为垃圾值不会在内存上得到清理吗?
2021-04-12 17:51:08

ES6:

Array.from(element.parentNode.children).indexOf(element)

解释 :

  • element.parentNode.children→ 返回 的兄弟element,包括该元素。

  • Array.from→ 将 的构造函数强制children转换为Array对象

  • indexOf→ 您可以申请,indexOf因为您现在有了Array对象。

但仅在 Chrome 45 和 Firefox 32 上可用,在 Internet Explorer 上根本不可用。
2021-03-15 17:51:08
迄今为止最优雅的解决方案:)
2021-03-21 17:51:08
Internet Explorer 还活着吗?Just Jock .. 好的,所以你需要一个polyfill才能Array.from在 Internet Explorer 上工作
2021-03-22 17:51:08
@TheDarkIn1978 我知道代码优雅和应用程序性能之间存在权衡👍🏻
2021-03-22 17:51:08
根据 MDN,调用Array.from() creates a new Array instance from an array-like or iterable object.创建一个新的数组实例只是为了找到一个索引可能不是内存或 GC 高效的,这取决于操作的频率,在这种情况下,如已接受的答案中所解释的那样,迭代会更多理想的。
2021-04-08 17:51:08

您可以使用该previousSibling属性遍历兄弟姐妹,直到返回null并计算遇到的兄弟姐妹数量:

var i = 0;
while( (child = child.previousSibling) != null ) 
  i++;
//at the end i will contain the index.

请注意,在 Java 等语言中,有一个getPreviousSibling()函数,但在 JS 中,这已成为一个属性 -- previousSibling

使用previousElementSiblingnextElementSibling忽略文本和注释节点。

@sfarbota Javascript 不知道块范围,因此i可以访问。
2021-03-13 17:51:08
一行版本: for (var i=0; (node=node.previousSibling); i++);
2021-03-20 17:51:08
@nepdev那将是因为之间的差异.previousSibling.previousElementSibling前者命中文本节点,后者没有。
2021-03-21 17:51:08
这种方法需要相同数量的迭代来确定子索引,所以我看不出它会快得多。
2021-03-26 17:51:08
是的。不过,您在文本中留下了 getPreviousSibling() 。
2021-04-11 17:51:08

ES——更短

[...element.parentNode.children].indexOf(element);

扩展运算符是一种快捷方式

childNodes 还包括文本节点
2021-03-17 17:51:08
使用typescript你会得到 Type 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
2021-03-18 17:51:08
什么之间的区别e.parentElement.childNodese.parentNode.children
2021-03-24 17:51:08
这是一个有趣的运算符。
2021-04-03 17:51:08

添加一个(安全前缀) element.getParentIndex():

Element.prototype.PREFIXgetParentIndex = function() {
  return Array.prototype.indexOf.call(this.parentNode.children, this);
}
小马填充比污染你不拥有的代码要安全得多。function getIndexFromParent(node){...}
2021-03-21 17:51:08
@JuanMendes 是的,如果您对函数而不是方法感到满意,ECMA265 委员会极不可能添加带有您前缀的方法。
2021-03-28 17:51:08
Web 开发的痛苦是有原因的:prefix-jumpy dev's。为什么不直接做if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }无论如何,如果将来将其实施到标准中,那么它很可能会像element.parentIndex. 所以,我会说最好的方法是if(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
2021-04-03 17:51:08
跳过辩论,不要做原型污染。一个普通的旧函数没有错。
2021-04-03 17:51:08
因为未来的getParentIndex()签名可能与您的实现不同。
2021-04-05 17:51:08