【问题标题】:When the innerHTML is modified, why does it seem like the element is replaced in the debugger console?修改 innerHTML 后,为什么在调试器控制台中看起来元素被替换了?
【发布时间】:2020-02-15 14:20:18
【问题描述】:

使用以下代码,在 Google Chrome 的开发工具中,它显示 root2 似乎每秒都在变化,但 root2 应该保持不变。如果说是root2的内容在变化,那么root1的内容也在更新,但不是每秒都在闪烁。这是为什么呢?

setInterval(function() {

  document.getElementById('root2').innerHTML = ("<h1>Hello, world!</h1><h2>" +
    new Date().toLocaleTimeString() + "</h2>");

}, 1000);
<div id="root1">
  <div id="root2"></div>
</div>

root2 每秒都在闪烁:

【问题讨论】:

    标签: javascript dom google-chrome-devtools


    【解决方案1】:

    因为它是。

    使用innerHtml 赋值实际上会丢弃“此节点中的所有内容”并根据您使用的 HTML 字符串引导 new 子节点。这些新节点可能使用与以前完全相同的属性,但它们仍然是全新的节点。

    但是,当使用innerHTML 时,您只是在更改节点子内容。不是节点本身。这就是为什么root1 没有显示任何变化的原因:它的孩子都没有被删除/添加。 root2 节点的子内容确实发生了变化,因此它会发出某些变化的信号。

    如果您想保留节点并只更新它们,请不要使用innerHTML。事实上,永远不要使用innerHTML,除非你真的知道你在做什么。对于您要解决/实施的任何问题或事物,它几乎从来都不是解决方案。

    在这种特定情况下,您似乎只想根据“反映更新后的 DOM 状态的新组合字符串”更新活动 DOM,请查看 morphDOM 之类的内容。

    【讨论】:

    • 被替换了?如果我在控制台中执行 e = document.getElementById('root2') 并在 10 秒后执行 e === document.getElementById('root2') 它仍然显示 true (这是在硬盘驱动器上的简单 HTML 文件中尝试的,而不是此处的 Snippet 或 JSFiddle,所以 e 确实是获得的元素,(与在 Snippet 或 JSFiddle 中,您无法轻松从 iframe 中获取元素))
    • innerHTML 会丢弃您设置innerHTML 的节点中的一切。 DOM 节点,JS 事件绑定等等等等,然后构建一个新的 DOM 树。我无法谈论如何评估平等,但如果这种平等成立,我会感到惊讶。有什么可以证明这一点的吗?
    • 你说得对,它扔掉“in这个节点的所有东西”,而不是节点本身,只有它的内容。
    【解决方案2】:

    因为它们确实会突出显示任何已删除节点的父节点:

    const sentence = 'click to remove last text node';
    root2.append.apply(root2, [...sentence]);
    
    onclick = e => {
      lastNode = root2.childNodes[ root2.childNodes.length - 1 ];
      if(lastNode) lastNode.remove();
    };
    <div id="root1">
      <div id="root2"></div>
    </div>

    它们也会突出显示任何成为 parentNode 的节点,因为它们会突出显示添加新节点的任何折叠节点:

    (async function loop() {
      root2.append("first node insertion highlights the new parentNode");
      await wait(1000);
      // removal does too, as shown in previous snippet
      [...root2.childNodes].forEach(node => node.remove());
      await wait(1000);
      loop();
    })();
    
    function wait(ms) { return new Promise(res => setTimeout(res, ms)); }
    <div id="root1">
      <div id="root2"></div>
    </div>

    所以当你改变你的元素的innerHTML时,这两种情况都会发生:

    • 首先删除其所有内容 => 突出显示,
    • 然后您的 Element 再次成为 parentNode => 突出显示。

    【讨论】:

      猜你喜欢
      • 2021-09-09
      • 2016-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 2011-10-01
      • 1970-01-01
      • 2022-12-21
      相关资源
      最近更新 更多