Можно ли добавить к innerHTML без уничтожения слушателей событий потомков?


в следующем примере кода прилагаю onclick обработчик событий для диапазона, содержащего текст "foo". Обработчик-это анонимная функция, которая выдает предупреждение ().

однако, если я назначаю родительскому узлу 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>
10 70

10 ответов:

к сожалению, задание innerHTML вызывает разрушение всех дочерних элементов, даже если вы пытаетесь добавить. Если вы хотите сохранить дочерние узлы (и их обработчики событий), вы должны использовать функции DOM:

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

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

Edit: решение Боба, из комментариев. Опубликуй свой ответ, Боб! Получить кредит на это. : -)

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

используя .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);

The 'beforeend' аргумент указывает место в элементе для вставки содержимого HTML. Варианты есть 'beforebegin','afterbegin','beforeend' и 'afterend'. Их соответствующие местоположения:

<!-- beforebegin -->
<div id="mydiv">
  <!-- afterbegin -->
  <p>Existing content in #mydiv</p>
  <!-- beforeend -->
</div>
<!-- afterend -->

теперь, это 2012, и jQuery имеет функции добавления и добавления, которые делают именно это, добавляют контент, не влияя на текущий контент. Очень полезно.

как небольшой (но связанный) asside, если вы используете библиотеку javascript, такую как jquery (v1.3), чтобы сделать свою манипуляцию dom, вы можете использовать живые события, посредством которых вы настраиваете обработчик, такой как:

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

и он будет применяться к этому селектору во все времена во время любого вида манипуляций с jquery. Для живых событий см.:docs.jquery.com/events/live для манипуляций с jquery см.:docs.jquery.com/manipulation

Я создал свою разметку для вставки в виде строки, так как это меньше кода и легче читать, чем работать с причудливым материалом 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);

потеря обработчиков событий, IMO, ошибка в том, как 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
}

есть еще одна альтернатива: использование 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 + = 'добавить все, что вы хотите';

Это сработало для меня. Я добавил кнопку для ввода текста с помощью этого решения

вы могли бы сделать это вот так:

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

Я ленивый программист. Я не использую DOM, потому что это похоже на дополнительную типизацию. Для меня, Чем меньше кода, тем лучше. Вот как я бы добавил " бар " без замены "foo":

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