是否可以在不破坏后代事件侦听器的情况下附加到innerHTML?

IT技术 javascript html innerhtml dom-events
2021-02-07 04:16:52

在以下示例代码中,我将onclick事件处理程序附加到包含文本“foo”的范围。处理程序是一个匿名函数,它弹出一个alert().

但是,如果我分配给父节点的innerHTML,则此onclick事件处理程序将被破坏 - 单击“foo”无法弹出警报框。

这是可以修复的吗?

<html>
 <head>
 <script type="text/javascript">

  function start () {
    myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    mydiv = document.getElementById("mydiv");
    mydiv.innerHTML += "bar";
  }

 </script>
 </head>

 <body onload="start()">
   <div id="mydiv" style="border: solid red 2px">
     <span id="myspan">foo</span>
   </div>
 </body>

</html>
6个回答

不幸的是,赋值会innerHTML导致所有子元素的破坏,即使您正在尝试追加。如果要保留子节点(及其事件处理程序),则需要使用DOM 函数

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    mydiv.appendChild(document.createTextNode("bar"));
}

编辑: Bob 的解决方案,来自评论。发布你的答案,鲍勃!获得荣誉。:-)

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    var newcontent = document.createElement('div');
    newcontent.innerHTML = "bar";

    while (newcontent.firstChild) {
        mydiv.appendChild(newcontent.firstChild);
    }
}
newcontent= document.createElement('div'); newcontent.innerHTML=任意_blob;而 (newcontent.firstChild) mydiv.appendChild(newcontent.firstChild);
2021-03-23 04:16:52
@bobince——我已经用你的技术更新了我的答案,因为你自己还没有发布。如果您创建自己的答案,请继续并回滚我的答案。:-)
2021-03-23 04:16:52
不错,鲍勃!如果您将其作为格式良好的答案发布,我会选择它。
2021-03-24 04:16:52
是否有可以附加任意 HTML 块的替代品?
2021-04-07 04:16:52
哦,最后一件事,您需要“var myspan”、“var newcontent”等以避免意外溢出全局变量。
2021-04-09 04:16:52

使用.insertAdjacentHTML()保留事件侦听器,所有主要浏览器都支持这是一个简单的单行替换.innerHTML.

var html_to_insert = "<p>New paragraph</p>";

// with .innerHTML, destroys event listeners
document.getElementById('mydiv').innerHTML += html_to_insert;

// with .insertAdjacentHTML, preserves event listeners
document.getElementById('mydiv').insertAdjacentHTML('beforeend', html_to_insert);

'beforeend'参数指定要在其中要插入的元素的HTML内容。选项包括'beforebegin''afterbegin''beforeend',和'afterend'它们对应的位置是:

<!-- beforebegin -->
<div id="mydiv">
  <!-- afterbegin -->
  <p>Existing content in #mydiv</p>
  <!-- beforeend -->
</div>
<!-- afterend -->
你救了我的一天!
2021-03-11 04:16:52
小心 Chrome / Edge 抱怨区分大小写:即afterbegin不被接受afterBegin是!
2021-03-12 04:16:52
最佳解决方案。谢谢!
2021-03-14 04:16:52

现在是 2012 年,jQuery 具有 append 和 prepend 函数,可以做到这一点,在不影响当前内容的情况下添加内容。很有用。

OP 不是在谈论 jQuery
2021-03-25 04:16:52
.insertAdjacentHTML 自 IE4 以来一直存在
2021-04-04 04:16:52
@JordonBedwell,老实说,我不知道为什么我说我以前做过什么。你是 100% 正确的。我觉得当时我只是简单地查看了一下却找不到它,但是……老实说,我没有任何借口。Esailija 甚至链接到该页面。
2021-04-06 04:16:52
@Tynach 是的,它是他们的 JavaScript 站点,对其进行了最好的记录:developer.mozilla.org/en-US/docs/Web/API/Element/...
2021-04-07 04:16:52
2021-04-09 04:16:52

顺便说一句(但相关),如果您使用诸如 jquery (v1.3) 之类的 javascript 库来进行 dom 操作,您可以利用实时事件来设置处理程序,例如:

 $("#myspan").live("click", function(){
  alert('hi');
});

它将在任何类型的 jquery 操作期间始终应用于该选择器。有关实时事件,请参阅:docs.jquery.com/events/live以了解 jquery 操作,请参阅:docs.jquery.com/manipulation

OP 不是在谈论 jQuery
2021-03-20 04:16:52

我创建了我的标记以作为字符串插入,因为它比使用花哨的 dom 内容更少代码且更易于阅读。

然后我把它变成了一个临时元素的innerHTML,这样我就可以把那个元素的唯一的孩子附加到身体上。

var html = '<div>';
html += 'Hello div!';
html += '</div>';

var tempElement = document.createElement('div');
tempElement.innerHTML = html;
document.getElementsByTagName('body')[0].appendChild(tempElement.firstChild);