【问题标题】:Why is element empty in IE after being removed from the DOM?为什么从 DOM 中删除后 IE 中的元素为空?
【发布时间】:2012-08-20 14:03:20
【问题描述】:

以下 HTML 和 JavaScript 取自此 jsFiddle 的部分内容: http://jsfiddle.net/stephenjwatkins/2j3ZB/3/

HTML:

<p class="source">
    Source
</p>
<div id="target">
    <p class="dummy">
        Target
    </p>
</div>
<button id="transfer-button">Transfer</button>

JavaScript:

var sourceEl = $('.source');
var targetEl = $('#target');

$('#transfer-button').click(function() {
    targetEl.html('<p class="dummy">Transferring...</p>');
    setTimeout(function() {
        // Source element will be empty on second attempt to append
        targetEl.html('').append(sourceEl);
    }, 750);
    return false;
});​

请注意,setTimeout 和虚拟文本只是用于视觉指示器。

正如我们所见,在源元素从 DOM 中追加和删除一次之后,IE(所有版本)将在任何进一步追加时向 DOM 添加一个空元素;而所有其他浏览器都会添加正确的非空元素。

另一个增加混乱的方面是 sourceEl 仍然有元素信息(例如sourceEl.attr('class') 将返回“source”)。

我知道缓解该问题的方法(例如sourceEl.clone()),但最好能更好地了解 IE 为何表现不同,以避免将来出现任何相关问题。

是什么导致IE中的源元素在替换元素后唯一为空?

【问题讨论】:

  • 在我看来是垃圾收集器的问题,而且 IE 的垃圾收集器似乎比其他浏览器更有效。让我们看看我是否可以详细说明..

标签: javascript jquery internet-explorer dom


【解决方案1】:

在我看来,IE 的行为是正确的,而其他浏览器则非常神奇。 这一切都源于你打电话的时候:

targetEl.html('<p class="dummy">Transferring...</p>');

这会从页面中删除sourceEl 元素。所以它不再存在。我猜其他浏览器正在记住 DOM 对象,因为仍然有一个变量引用它。但 IE 将其识别为页面上不再存在,因此它丢失了引用。

正如您所提到的,我建议您在单击时克隆对象。这会在 JavaScript 中创建一个新对象。幸运的是,覆盖相同的变量是可行的。

    sourceEl = sourceEl.clone();

http://jsfiddle.net/AbJQE/3/

编辑 您还可以在插入新的源对象之前删除任何可能存在的原始源对象。这解决了触发快乐点击者的问题:

setTimeout(function() {
    $('.source').remove();
    targetEl.html('').append(sourceEl);
}, 750);

【讨论】:

  • 这可以澄清一下:targetEl.html('&lt;p class="dummy"&gt;Transferring...&lt;/p&gt;');第二次调用。当然,可能只是我之前有点脑死。
  • 但是在第一次点击的过程中它不会说“Transferring”?
  • 实际上,即使是我澄清的建议也是错误的......第一次调用不会对任何具有“.source”类的项目做任何事情,因为您还没有触及任何此类项目。 计时器结束后的任何调用都会删除 sourceEl,因为它实际上位于 targetEl 的 innerHTML 中(就像 Fabrico 所说的那样)。
  • (Fabrico 提到了第二次点击……这通常是第二次调用,除非您点击满意)。
  • rofl @JayC,是的,第二次调用。那时source 元素位于innerHTML 覆盖的元素内。
【解决方案2】:

首先让我们强调重要的部分:

  1. (第一次单击)获取source 元素并将其放入target 元素中;
  2. (第二次点击)清空target 元素并向其附加一个新子元素 (p.dummy),从而有效地从 DOM 中删除 source
  3. 清空 target 元素并尝试重新附加 source,它已不再存在于 DOM 中。

乍一看,这在任何浏览器中都不起作用,因为 source 元素已从 DOM 中删除。这里的“魔法”是 JavaScript 的Garbage Collector。浏览器会看到 sourceEl 仍然是作用域(在 setTimeout 闭包内),并且不会丢弃 sourceEl jQuery 对象内的引用 DOM 元素。

这里的问题不是 JScript(Microsft 的 Javascript 实现)的垃圾收集器,而是 JScript 在设置元素的innerHTML 时如何处理 DOM 解析。

其他浏览器将简单地分离所有childNodes(当没有更多活动引用时,它们将被GC收集)并将传递的html字符串解析为DOM元素,将它们附加到DOM。另一方面,Jscript 也会删除分离的childNodes'innerHTML/childNodes。查看此fiddle 以获取插图。

该元素实际上仍然存在于 IE 中并附加到 DOM 中:

它不再有childNodes。

为了防止这种行为,.clone() 元素(如问题中所述)或 .detach() 在其父元素上调用 .html() 之前,如果您打算重新使用该元素而不是“覆盖”它。

这是一个fiddle,在元素被覆盖之前使用.detach(),在所有浏览器中都可以正常工作。

【讨论】:

  • 我意识到问题不是 JScript 的 GC 而是它的 innerHTML,因此不得不起床解决这个问题。如果有人要添加 ECMAScript 或 JScript 实现规范,请随时添加。
  • +1 非常彻底的调查来回答这个问题。我还首先认为这是一个垃圾收集问题;但是,如果 IE 看​​到其他元素属性仍然存在,这将是一个 innerHTML 怪癖,这是有道理的。
  • @StephenWatkins 是的,在说明之前我还做了一些测试 - 我存储了元素的 .contents()(包括 textNodes)以确保它不是问题IE 的 GC——textNodes 仍然被缓存,但被innerHTML“清空”。
猜你喜欢
  • 2015-12-13
  • 2014-09-29
  • 2016-10-17
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多