【问题标题】:DOM: cropping an element and using parentNodeDOM:裁剪元素并使用 parentNode
【发布时间】:2013-06-26 07:02:41
【问题描述】:

考虑这个简单的页面:

<html>
<head>
<script>
    var upper;
    var lower;

    function crop() {
      //upper = document.getElementById('upper');
      lower = document.getElementById('lower');
      document.body.innerHTML = '';  
      document.body.appendChild(lower.cloneNode(true));
    }

    function up() {
      document.body.innerHTML = '';  
      document.body.appendChild(lower.parentNode);
    }
</script>
</head>
<body>
    <div id="upper">
      Upper Div
      <div id="lower">
        Lower Div
        <button onclick="crop()">Crop</button>
        <button onclick="up()">Up</button>
      </div>
    </div>
</body>
</html>

所以Crop 按钮清除正文,克隆下部 div 并将其附加到正文。 Up 按钮的目的是使下部 div 的父级可见 (upper div)。在我的第一次尝试中,我尝试使用lower.parentNode,但它不起作用,因为它是null。我认为这是因为变量 lower 现在指向一个 DOM 元素,它不是正文的一部分。 (我的理解正确吗?)但是现在考虑一下注释行:

//upper = document.getElementById('upper');

除了获取对上层 div 的引用之外什么都不做。当我取消注释此行时,up() 开始工作。这里奇怪的是我没有以任何方式使用这个变量。你能解释一下这种行为吗?

【问题讨论】:

标签: javascript dom


【解决方案1】:

当您设置document.body.innerHTML = ''; 时,您将从DOM 树 中删除&lt;body&gt; 的所有子节点,但不会破坏这些节点本身的树结构。如果不存在对这些节点的引用,它们也会被销毁并被垃圾回收。

你已经设置了(global)lower = document.getElementById('lower');,所以存在对&lt;div id="lower"&gt;的引用,这意味着虽然它可能会从DOM树中移除,它不会被破坏或垃圾收集,因为它被此引用“保持活力”。

现在奇怪的东西来了,因为您将 String 方法 (.innerHTML) 与 DOM 方法 (getElementById, appendChild) 混合在一起,浏览器不确定从垃圾收集中保存什么。它最终决定 childNodes 的引用节点可以保留,但 parentNodes 的结合力不够强,所以被摧毁。这意味着你不统一得到null,你也可以得到

Uncaught Error: NotFoundError: DOM Exception 8 

当您设置 (global) upper 时,这会保存 &lt;div id="upper"&gt;,因为您现在有一个引用来保持它的活动状态。它还保存了&lt;div id="lower"&gt;,因为upperchildNodes 也受到了垃圾回收的保护。这会保留它们之间的 childNode / parentNode 链接。


另外值得注意的是cloneNode可能会导致id属性冲突,因为一个id必须是唯一的,但是根据定义,克隆不是唯一的。

【讨论】:

  • cloneNode 不会删除任何属性。
  • @RobG 你说得对,我以前遇到The duplicate node returned by cloneNode() receives a new uniqueID when it is added to another node 的时候一定在经历过。
  • 请注意,MDN 是一个社区 Wiki,它根本不具有权威性(例如,我不知道是否有任何 Mozilla 开发人员做出贡献)。无论如何,这种说法显然是错误的,很快就会被删除……:-)
  • 感谢您的回答。那么有没有办法确保暂时从document.body 中删除的元素不会被垃圾收集?理想情况下,我希望能够连续单击Up,直到我到达顶部。持有对层次结构中每个节点的引用似乎很难。
  • 您只需要保存对祖先节点(父节点、父节点的父节点等)的引用,而不是每个节点。请注意,一旦您设置了document.body.innerHTMLdocument.body 将不再是祖先节点。
【解决方案2】:

您创建一个名为 upper 的全局变量。当你运行 crop 时,你分配一个对 id 为 upper 的元素的引用,它被存储为一个全局变量,并且无论你做什么,它仍然可以作为一个引用该元素的全局变量对 DOM 执行操作。

编辑

进一步解释一下,通过保留 upper,您还保留了它的所有后代及其关系,因此在清除 body 后 lower.parentNode 仍然存在。但是如果你不保留对 upper 的引用,那么清除 body 也会删除 lower 的任何父级或兄弟级,但不会删除 lower 的后代时间>。

【讨论】:

  • 是的,但他没有在任何地方使用变量 upper
  • "He" 是指分配给 upper 的语句未注释并调用 crop 时。
猜你喜欢
  • 2019-07-25
  • 2016-09-18
  • 2022-07-27
  • 2015-06-14
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
  • 2023-03-24
  • 2017-08-09
相关资源
最近更新 更多