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

问题描述 投票:0回答:14

在以下示例代码中,我将

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>
javascript html innerhtml dom-events
14个回答
187
投票

使用

.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 -->

159
投票

不幸的是,对

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

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

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

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

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);
    }
}

3
投票

现在是 2012 年了,jQuery 具有附加和前置函数来完成此操作,添加内容而不影响当前内容。非常有用。


3
投票

我创建了我的标记作为字符串插入,因为它比使用花哨的 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);

1
投票

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

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

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


1
投票

还有另一种选择:使用

setAttribute
而不是添加事件侦听器。像这样:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo innerHTML and event listeners</title>
<style>
    div {
        border: 1px solid black;
        padding: 10px;
    }
</style>
</head>
<body>
    <div>
        <span>Click here.</span>
    </div>
    <script>
        document.querySelector('span').setAttribute("onclick","alert('Hi.')");
        document.querySelector('div').innerHTML += ' Added text.';
    </script>
</body>
</html>


1
投票

是的,如果您直接在模板中使用标签属性

onclick="sayHi()"
绑定事件,就像您的
<body onload="start()">
一样,这是可能的 - 这种方法类似于框架Angular/Vue/React/等。您还可以使用
<template>
来操作“动态”html,如here。它不是严格的不引人注目的 js,但是对于小型项目来说它是可接受的

function start() { mydiv.innerHTML += "bar"; } function sayHi() { alert("hi"); }
<body onload="start()">
  <div id="mydiv" style="border: solid red 2px">
    <span id="myspan" onclick="sayHi()">foo</span>
  </div>
</body>


0
投票
在我看来,丢失事件处理程序是 Javascript 处理 DOM 方式中的一个错误。为了避免这种行为,您可以添加以下内容:

function start () { myspan = document.getElementById("myspan"); myspan.onclick = function() { alert ("hi"); }; mydiv = document.getElementById("mydiv"); clickHandler = mydiv.onclick; // add mydiv.innerHTML += "bar"; mydiv.onclick = clickHandler; // add }
    

0
投票
最简单的方法是使用数组并将元素推入其中,然后将数组后续值动态插入到数组中。 这是我的代码:

var namesArray = []; function myclick(){ var readhere = prompt ("Insert value"); namesArray.push(readhere); document.getElementById('demo').innerHTML= namesArray; }
    

0
投票

Element#append

 可用于在另一个元素的末尾插入元素。要将 HTML 作为字符串插入,可以使用 Range#createContextualFragment

const myspan = document.getElementById("myspan"); myspan.append(document.createRange().createContextualFragment(` <div>Some HTML here</div> `));
或者仅附加文本:

myspan.append("some text"); // no need for document.createTextNode
如果不需要直接插入 HTML,请考虑使用 DOM 方法来创建结构:

myspan.append( Object.assign(document.createElement('div'), { textContent: 'some text', className: 'my-class' }), document.createElement('hr'), "some more text" ); // can append multiple elements (mixed with strings which are converted to text nodes)
相关说明,相应的 

Element#prepend

 方法可用于在元素的开头(第一个子元素之前)插入元素。
    


-1
投票
你可以这样做:

var anchors = document.getElementsByTagName('a'); var index_a = 0; var uls = document.getElementsByTagName('UL'); window.onload=function() {alert(anchors.length);}; for(var i=0 ; i<uls.length; i++) { lis = uls[i].getElementsByTagName('LI'); for(var j=0 ;j<lis.length;j++) { var first = lis[j].innerHTML; string = "<img src=\"http://g.etfv.co/" + anchors[index_a++] + "\" width=\"32\" height=\"32\" /> " + first; lis[j].innerHTML = string; } }
    

-1
投票
something.innerHTML += '添加你想要的任何内容';

它对我有用。我使用此解决方案向输入文本添加了一个按钮


-1
投票
对于任何带有标题和数据的对象数组。

jsfiddle



https://jsfiddle.net/AmrendraKumar/9ac75Lg0/2/

<table id="myTable" border='1|1'></table> <script> const userObjectArray = [{ name: "Ajay", age: 27, height: 5.10, address: "Bangalore" }, { name: "Vijay", age: 24, height: 5.10, address: "Bangalore" }, { name: "Dinesh", age: 27, height: 5.10, address: "Bangalore" }]; const headers = Object.keys(userObjectArray[0]); var tr1 = document.createElement('tr'); var htmlHeaderStr = ''; for (let i = 0; i < headers.length; i++) { htmlHeaderStr += "<th>" + headers[i] + "</th>" } tr1.innerHTML = htmlHeaderStr; document.getElementById('myTable').appendChild(tr1); for (var j = 0; j < userObjectArray.length; j++) { var tr = document.createElement('tr'); var htmlDataString = ''; for (var k = 0; k < headers.length; k++) { htmlDataString += "<td>" + userObjectArray[j][headers[k]] + "</td>" } tr.innerHTML = htmlDataString; document.getElementById('myTable').appendChild(tr); } </script>
    

-7
投票
我是一个懒惰的程序员。我不使用 DOM,因为它看起来像是额外的输入。对我来说,代码越少越好。以下是我添加“bar”而不替换“foo”的方法:

function start(){ var innermyspan = document.getElementById("myspan").innerHTML; document.getElementById("myspan").innerHTML=innermyspan+"bar"; }
    
© www.soinside.com 2019 - 2024. All rights reserved.