如何在纯JavaScript中获取给定元素的所有父节点?

rsk*_*k82 23 javascript dom

我的意思是他们的一系列.这是从顶级HTML到目标元素的链,包括元素本身.

例如,对于元素<A>,它将是:

[HTML, BODY, DIV, DIV, P, SPAN, A]
Run Code Online (Sandbox Code Playgroud)

Way*_*ett 39

稍短(更安全,因为target可能找不到):

var a = document.getElementById("target");
var els = [];
while (a) {
    els.unshift(a);
    a = a.parentNode;
}
Run Code Online (Sandbox Code Playgroud)

  • 我改变了接受的答案.这是最优雅的.(顺便说一句,测试显示推,然后反向更有效.)[我希望有一个选项可以接受多个答案,即使以我的积分为代价.] (6认同)
  • 这将包括文档节点。如果您希望在 `HTML` 元素处停止,请将 'a = a.parentNode' 更改为 `a = a.parentElement` (2认同)
  • 更优雅,只是为了好玩:`const parents = node =&gt; (node.parentElement ? parents(node.parentElement) : []).concat([node]);` (2认同)

tec*_*bar 19

您可以尝试以下方式:

var nodes = [];
var element = document.getElementById('yourelement');
nodes.push(element);
while(element.parentNode) {
    nodes.unshift(element.parentNode);
    element = element.parentNode;
}
Run Code Online (Sandbox Code Playgroud)

  • +1.也打败了我,但最后不是使用`reverse()`,而是使用`unshift()`而不是`push()` (4认同)
  • 请参阅http://jsperf.com/unshift-vs-push-reverse/3了解性能结果 (3认同)
  • +1。一直以来我都不知道`.push()`有一个叫`.unshift()`的兄弟! (2认同)
  • 如果我们都这么担心速度,为什么不是 `varnodes = [element];` 并交换前两行,并删除循环之前的 `push` 。我认为“push”然后“reverse”也更快。重复的“unshift”将是 O(n^2),因为每次迭代你必须移动越来越多的元素。“push”然后“reverse”可以利用经过推送优化的数组和就地反向操作。在合理的实现中,推送可能会以恒定的时间摊销。`reverse` 的复杂度是 O(n),就地,超快。 (2认同)

Yur*_*hov 8

我喜欢这个方法:

[...(function*(e){do { yield e; } while (e = e.parentNode);})($0)]
Run Code Online (Sandbox Code Playgroud)

...其中 $0 是您的元素。

此方法的一个优点是它可以用作表达式中的值。

要获取没有目标元素的数组:

[...(function*(e){while (e = e.parentNode) { yield e; }})($0)]
Run Code Online (Sandbox Code Playgroud)

  • 为了排除目标元素,将 do-while 反转为 while 循环会更容易,如下所示: `[...(function*(e){while (e = e.parentNode) { yield e; }}) ($0)]`(我已经更新了我的答案) (3认同)

Nat*_*nes 5

您可以遍历 s 链,element.parentNode直到达到 false 值,并在执行过程中附加到数组:

const getParents = el => {
  for (var parents = []; el; el = el.parentNode) {
    parents.push(el);
  }

  return parents;
};

const el = document.querySelector("b");
console.log(getParents(el).reverse().map(e => e.nodeName));
Run Code Online (Sandbox Code Playgroud)
<div><p><span><b>Foo</b></span></div>
Run Code Online (Sandbox Code Playgroud)

请注意,反转是在调用方中完成的,因为它对于沿袭算法来说并不是必需的。映射到e.nodeName纯粹是为了演示,也不是必需的。

请注意,这种方法意味着您最终会将文档元素作为链中的最后一个元素。如果您不想这样做,可以添加&& el !== document循环停止条件。

上面代码的总体时间复杂度是线性的并且reverse()是就地的,因此不需要额外的分配。unshift正如其他一些答案所建议的那样,循环中的循环是二次的,并且可能会损害异常深的 DOM 树的可扩展性,以换取可忽略不计的优雅增益。