4

以下 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 中唯一为空?

4

2 回答 2

7

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

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

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

这里的问题不是 JScript(Microsft 的 Javascript 实现)的垃圾收集器,而是 JScript 在设置元素的innerHTML.

其他浏览器将简单地分离所有childNodes(当没有更多活动引用时,GC 将收集这些 s)并将传递的 html 字符串解析为 DOM 元素,将它们附加到 DOM 中。另一方面,Jscript 也会擦除分离childNode的 s' innerHTML/ childNodes。检查这个小提琴的插图。

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

在此处输入图像描述

它只是没有childNodes了。

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

这是在覆盖元素之前使用的小提琴,在所有浏览器中都可以正常工作。.detach()

于 2012-08-25T05:17:45.627 回答
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);
于 2012-08-25T04:39:47.807 回答