为啥使用 element.innerHTML 后事件监听器会停止工作?

Posted

技术标签:

【中文标题】为啥使用 element.innerHTML 后事件监听器会停止工作?【英文标题】:Why can event listeners stop working after using element.innerHTML?为什么使用 element.innerHTML 后事件监听器会停止工作? 【发布时间】:2016-09-23 17:39:40 【问题描述】:

我是 javascript 的初学者。一本 JavaScript 书说element.innerhtml 的一个缺点是:

事件处理程序可能不再按预期工作。

我不明白这是什么意思。谁能举个例子?

【问题讨论】:

这是一个数组/JSON 类比:var obj = [Infinity]; var str = JSON.stringify(obj); str = str.slice(0, -1) + ', 42]'; obj = JSON.parse(str);。这是向数组添加新元素的一种非常可怕的方式。结果是数组[null, 42],因为JSON 不能代表Infinity。与 DOM 类似,任何绑定到元素的事件处理程序在转换为 HTML 时都会丢失,因为 HTML 本身无法存储绑定函数的表示。 【参考方案1】:

很可能,它指的是一些人用来在末尾插入 HTML 的技术:

element.innerHTML += "inserted HTML";

这将获取当前的 HTML,将其与插入的 HTML 连接起来,然后全部解析。

作为副作用,现有元素的所有内部状态(如事件侦听器、已检查状态等)都将丢失。

var btn = document.querySelector("button");
btn.addEventListener("click", function() 
  btn.textContent = "I won't work anymore";
  document.body.innerHTML += "<p>Inserted text</p>";
);
&lt;button&gt;Click me to insert HTML&lt;/button&gt;

相反,如果你想在一个元素的末尾插入一些 HTML,你可以使用

element.insertAdjacentHTML('beforeend', "inserted HTML");

这将保留现有元素。

var btn = document.querySelector("button");
btn.addEventListener("click", function() 
  btn.textContent = "I still work";
  document.body.insertAdjacentHTML("beforeend", "<p>Inserted text</p>");
);
&lt;button&gt;Click me to insert HTML&lt;/button&gt;

如果您不介意将插入的内容包装在元素中,另一种选择是使用appendChild

var btn = document.querySelector("button");
btn.addEventListener("click", function() 
  btn.textContent = "I still work";
  var wrapper = document.createElement('div');
  wrapper.innerHTML = "<p>Inserted text</p>";
  document.body.appendChild(wrapper);
);
&lt;button&gt;Click me to insert HTML&lt;/button&gt;

【讨论】:

【参考方案2】:

innerHTML元素的html内容的字符串表示。获取这些内容没有副作用,但重置它会强制浏览器生成 new 元素。

文档中的每个 HTML 标记都被浏览器解析为唯一的 DOM HTMLElement 对象。事件处理程序绑定到这些元素。通过重置innerHTML 属性,浏览器会移除旧元素,并使DOM 解析器根据新的html 字符串创建其他元素对象。当一个元素被移除时,它的事件处理程序也被移除。

假设您有一个元素通过处理程序响应它的点击事件,当元素被删除时,您无法单击它,因此您会觉得处理程序也被删除了。事件处理程序的垃圾收集方式取决于已编写的代码和 JavaScript 解释器的工作方式。

【讨论】:

【参考方案3】:

因为当您使用 Javascript 和 element.innerHTML 函数动态创建元素时,新创建的元素可能无法按预期响应事件侦听器方法。

【讨论】:

以上是关于为啥使用 element.innerHTML 后事件监听器会停止工作?的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS element.innerHTML 在指令内未定义

通过纯 JS 从 tablerow//<tr onClick(myFunction> 获取 element.innerHTML

HTML innerText

Java对象的"后事处理"——垃圾回收

Java对象"后事处理"那点事儿——垃圾回收

为啥还有内存,SWAP怎么都用上了