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

在下面的示例代码中,我将一个 onclick事件处理程序附加到包含文本“ foo”的 span。处理程序是一个弹出 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>
379711 次浏览

不幸的是,对 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);
}
}

在我看来,丢失事件处理程序是 Javascript 处理 DOM 的一个 bug。为了避免这种行为,可以添加以下内容:

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
}

另外,如果你使用 jquery (v1.3)这样的 javascript 库来进行 Dom 操作,你可以利用活动事件来设置一个处理程序,比如:

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

并且在任何类型的 jquery 操作期间,它将始终应用于该选择器。有关活动事件,请参见: Docs.jquery.com/events/live有关 jquery 操作,请参见: Docs.jquery.com/manipulation

我是个懒惰的程序员。我不使用 DOM,因为它看起来像额外的输入。对我来说,代码越少越好。下面是我如何在不替换“ foo”的情况下添加“ bar”:

function start(){
var innermyspan = document.getElementById("myspan").innerHTML;
document.getElementById("myspan").innerHTML=innermyspan+"bar";
}

现在是2012年了,jQuery 有追加和预置函数来完成这项工作,添加内容而不影响当前内容。非常有用。

我创建我的标记作为字符串插入,因为它的代码更少,更容易阅读,而不是使用花哨的 dom 东西。

然后,我将 innerHTML 设置为一个临时元素,这样我就可以获取该元素的唯一子元素并附加到 body。

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


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

你可以这样做:

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

使用 .insertAdjacentHTML()保留事件侦听器和 所有主流浏览器都支持

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

还有另一种选择: 使用 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>

InnerHTML + = ‘ add whatever you want’;

我用这个解决方案在输入文本中添加了一个按钮

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

var namesArray = [];


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

是的,如果您使用标记属性 onclick="sayHi()"直接在模板中绑定事件,这是可能的,类似于您的 <body onload="start()">-这种方法类似于框架 angle/vue/response/等。你也可以使用 <template>来操作“动态”html,比如 给你。它不是严格的不引人注目的 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>

对于包含头和 data.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>