Можно ли добавить к innerHTML без уничтожения прослушивателей событий потомков?
В следующем примере кода я прикрепляю обработчик события 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>
Ответы
Ответ 1
К сожалению, назначение 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);
}
}
Ответ 2
Использование .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 -->
Ответ 3
Теперь это 2012 год, и у jQuery есть функции добавления и добавления, которые делают именно это, добавляют контент, не влияя на текущий контент. Очень полезно.
Ответ 4
Как небольшой (но связанный) asside, если вы используете javascript-библиотеку, такую как jquery (v1.3) для выполнения манипуляции с dom, вы можете использовать живые события, в которых вы настраиваете обработчик, например:
$("#myspan").live("click", function(){
alert('hi');
});
и он будет применяться к этому селектору в любое время при любых манипуляциях с jquery. Для живых событий см. docs.jquery.com/events/live для обработки jquery см.: docs.jquery.com/manipulation
Ответ 5
something.innerHTML + = 'добавить все, что хотите ";
это сработало для меня. Я добавил кнопку для ввода текста, используя это решение.
Ответ 6
Я создал свою разметку для вставки в виде строки, поскольку она меньше кода и ее легче читать, чем работать с файлом fancy 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);
Ответ 7
Существует еще одна альтернатива: использование 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>
Ответ 8
Потеря обработчиков событий - это ИМО, ошибка в том, как 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
}
Ответ 9
Вы можете сделать это следующим образом:
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;
}
}
Ответ 10
Самый простой способ - использовать массив и помещать в него элементы, а затем динамически вставлять последующие значения массива в массив. Вот мой код:
var namesArray = [];
function myclick(){
var readhere = prompt ("Insert value");
namesArray.push(readhere);
document.getElementById('demo').innerHTML= namesArray;
}
Ответ 11
Да, это возможно, если вы связываете события, используя аргумент onclick="sayHi()"
непосредственно в шаблоне, аналогично вашему <body onload="start()">
- этот подход аналогичен фреймворкам angular/vue/реакции/и т. Вы также можете использовать <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>
Ответ 12
Для любого массива объектов с заголовком и данными. 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>
Ответ 13
Я ленивый программист. Я не использую DOM, потому что это похоже на дополнительную типизацию. Для меня, чем меньше код, тем лучше. Вот как я бы добавил "bar", не заменяя "foo":
function start(){
var innermyspan = document.getElementById("myspan").innerHTML;
document.getElementById("myspan").innerHTML=innermyspan+"bar";
}