Альтернатива jQuery для замены HTML без прерывания прослушивателей событий

В определенный момент моего кода мне нужно взять html-строку, полученную из AJAX-запроса, и заменить на нее определенный контейнер.

У меня есть это, но, как указано в нескольких ссылках в Интернете, это сборка мусора и освобождает слушателей событий

this.rightPanel.innerHTML = content;

Это, однако, не происходит с JQuery .html() функция, которая поддерживает работу слушателей событий,

$(this.rightPanel).html(content);

работает без изъянов.

Я не хотел использовать jQuery для манипулирования DOM, даже если браузеры поддерживают его изначально. Какая лучшая альтернатива для меня - воспроизвести то же поведение, что и в jQuery? .html()?

Спасибо

1 ответ

Решение

Однако этого не происходит с функцией jQuery .html()...

Да, это так.

... который поддерживает работу слушателей события...

Нет, это не так.:-)

Похоже, они делают то же самое со слушателями событий:

// DOM
document.getElementById("btn1").addEventListener("click", function() {
  console.log("Button 1");
});

// jQuery
$("#btn2").on("click", function() {
  console.log("Button 2");
});

// Replace 'em
$("#btnRep").on("click", function() {
  var wrap1 = document.getElementById("wrap1");
  wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
  var wrap2 = $("#wrap2");
  wrap2.html(wrap2.html() + " (replaced)");
});
<p>Click Button 1, then Button 2, Then Replace, then Buttons 1 and 2 again -- you'll see *neither* of them has a handler anymore after being replaced.</p>
<div id="wrap1">
  <input type="button" id="btn1" value="Button 1">
</div>
<div id="wrap2">
  <input type="button" id="btn2" value="Button 2">
</div>
<input type="button" id="btnRep" value="Replace">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Вероятно, вы видели, что jQuery делает делегирование событий действительно очень простым: вот где вы на самом деле подключаете событие к элементу-предку (возможно, даже body), но вы просите jQuery запускать ваш обработчик, только если он прошел через элемент во время всплытия. Таким образом, вы можете заменить элементы-потомки, потому что прослушиватель событий находится не на них, а на контейнере / предке.

Вы можете сделать это и без jQuery, это просто немного больше работы:

function addDelegated(element, eventName, selector, handler) {
  element.addEventListener(eventName, function(e) {
    // Start with the target element, and go through its parents
    // until we reach the element we hooked the event on (`this`)
    var element = e.target;
    while (element && element !== this) {
        // `matches` test the element against a CSS selector
        if (element.matches(selector)) {
          // Yes, trigger the handler
          return handler.call(element, e);
        }
        element = element.parentNode;
    }
  });
}

// Hook the event on wrap1
addDelegated(document.getElementById("wrap1"), "click", "#btn1", function() {
  console.log("Button 1");
});

// Replace
document.getElementById("btnRep").addEventListener("click", function() {
  var wrap1 = document.getElementById("wrap1");
  wrap1.innerHTML = wrap1.innerHTML + " (replaced)";
});
<p>Click Button 1, then Replace, then Button 1 again.</p>
<div id="wrap1">
  <input type="button" id="btn1" value="Button 1">
</div>
<input type="button" id="btnRep" value="Replace">

Другие вопросы по тегам