从DOM中删除后,为什么IE中的元素为空?

时间:2012-08-25 03:53:37

标签: javascript jquery internet-explorer dom

以下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')将返回&#34; source&#34;)。

我知道缓解这个问题的方法(例如sourceEl.clone()),但是如果能够更好地理解为什么IE的行为方式不同以避免将来出现任何相关问题,那将会很好。

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

2 个答案:

答案 0 :(得分:6)

首先让我们重点介绍一下重要部分:

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

  4. 初看起来,这不适用于任何浏览器,因为source元素已从DOM中删除。这里的“神奇”是JavaScript的Garbage Collector。浏览器看到sourceEl仍然是作用域的(在setTimeout闭包内)并且不会将引用的DOM元素遗留在sourceEl jQuery对象中。

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

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

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

    enter image description here

    它再也没有childNode了。

    要防止出现此类行为,.clone()元素(如问题中所述)或.detach()之前,如果您打算重新使用其父级,请先调用.html()元素而不是“覆盖”它。

    在覆盖元素之前使用.detach() fiddle,在所有浏览器中都能正常使用。

答案 1 :(得分:2)

在我看来,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);