javascript - 为什么要 y.innerHTML = x.innerHTML;避免?

标签 javascript jquery html browser

假设我们在页面上有一个 DIV x,我们想将那个 DIV 的内容复制(“复制粘贴”)到另一个 DIV y 中。我们可以这样做:

y.innerHTML = x.innerHTML;

或使用 jQuery:

$(y).html( $(x).html() );

但是,这种方法似乎不是一个好主意,应该避免使用。

(1)为什么要避免这种方法?

(2) 应该怎么做呢?


更新:
对于这个问题,我们假设 DIV x 中没有带 ID 的元素。
(抱歉,我忘了在我原来的问题中提到这个案例。)

结论:
我已经在下面发布了我自己对这个问题的回答(正如我最初打算的那样)。现在,我也打算接受我自己的答案 :P,但是 lonesomeday 的答案太神奇了,我不得不接受它。

最佳答案

这种将 HTML 元素从一个地方“复制”到另一个地方的方法是对浏览器行为的误解的结果。浏览器不会将 HTML 文档保存在内存中的某个地方,并根据来自 JavaScript 的命令重复修改 HTML。

当浏览器首次加载页面时,它会解析 HTML 文档并将其转换为 DOM 结构。这是遵循 W3C 标准的对象关系(好吧,主要是……)。原来的 HTML 从那时起就完全多余了。浏览器不关心原始的 HTML 结构是什么;它对网页的理解是从中创建的 DOM 结构。如果您的 HTML 标记不正确/无效,Web 浏览器将以某种方式对其进行更正; DOM 结构不会以任何方式包含无效代码。

基本上,HTML 应该被视为一种序列化 DOM 结构的方式,以便通过 Internet 传递或存储在本地文件中。

因此,不应将其用于修改现有网页。 DOM(文档对象模型)有一个用于更改页面内容的系统。这是基于节点的关系,而不是基于 HTML 序列化。所以当你添加 liul ,您有以下两个选项(假设 ul 是列表元素):

// option 1: innerHTML
ul.innerHTML += '<li>foobar</li>';

// option 2: DOM manipulation
var li = document.createElement('li');
li.appendChild(document.createTextNode('foobar'));
ul.appendChild(li);

现在,第一个选项看起来简单多了,但这只是因为浏览器为您抽象了很多:在内部,浏览器必须将元素的子元素转换为字符串,然后附加一些内容,然后转换字符串返回到 DOM 结构。第二个选项对应于浏览器对正在发生的事情的 native 理解。

第二个主要考虑因素是考虑 HTML 的局限性。当您考虑网页时,并非所有与元素相关的内容都可以序列化为 HTML。例如,与 x.onclick = function(); 绑定(bind)的事件处理程序或 x.addEventListener(...)不会在 innerHTML 中复制, 所以它们不会被复制。所以 y 中的新元素不会有事件监听器。这可能不是您想要的。

所以解决这个问题的方法是使用 native DOM 方法:

for (var i = 0; i < x.childNodes.length; i++) {
    y.appendChild(x.childNodes[i].cloneNode(true));
}

阅读 MDN 文档可能有助于理解这种做事方式:

现在这个问题(与上面代码示例中的选项 2 一样)是它非常冗长,比 innerHTML 长得多选项将是。这是当你欣赏拥有一个 JavaScript 库来为你做这种事情的时候。例如,在 jQuery 中:

$('#y').html($('#x').clone(true, true).contents());

这更明确地说明了您想要发生的事情。例如,除了具有各种性能优势和保留事件处理程序外,它还可以帮助您了解代码的作用。这对您作为 JavaScript 程序员的灵魂有好处,并且可以大大降低出现奇怪错误的可能性!

关于javascript - 为什么要 y.innerHTML = x.innerHTML;避免?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7392930/

相关文章:

javascript - 用 JS 解析 JSON foreach,显示 HTML 列表

javascript - 只需运行一次 location.reload 方法

javascript - 如何在 jquery 2.1 中使用 .toggle

javascript - jquery 数据表 : how to shift columns mappings (because of inserted "row header column")?

javascript - Spark 2.0.0 - JSON 格式错误的输出

javascript - 如何根据第一个选择下拉菜单显示选择下拉菜单

javascript - 提交 MVC 后禁用 BootstrapButton

javascript - 似乎无法将 CSS 和 JS 加载到 JSF 文件

HTML 表格截断文本但尽可能适合

javascript - 在 Handlebars 模板上声明数据表