Подтвердить что ты не робот

Как скопировать DOM node с прослушивателями событий?

Я пробовал

node.cloneNode(true); // deep copy

Кажется, он не копирует прослушиватели событий, которые я добавил с помощью node.addEventListener("click", someFunc);.

Мы используем библиотеку Dojo.

4b9b3361

Ответ 1

cloneNode() не копирует прослушиватели событий. На самом деле, нет способа получить прослушиватели событий через DOM после их подключения, поэтому ваши варианты:

  • Добавьте всех прослушивателей событий вручную к клонированным node
  • Рефакторинг вашего кода для использования делегирования делегирования, чтобы все обработчики событий были привязаны к node, который содержит как оригинал, так и клон
  • Используйте функцию обертки вокруг Node.addEventListener(), чтобы отслеживать слушателей, добавленных к каждому node. Например, метод jQuery clone() может скопировать node с его прослушивателями событий.

Ответ 2

Пример делегирования события.

Прочитав ответ Тима Дауна, я обнаружил, что делегированные события очень легко реализовать, решая аналогичную проблему, с которой я столкнулся. Я думал, что добавлю конкретный пример, хотя это в JQuery, а не в Dojo.

Я пересматриваю приложение в семантическом интерфейсе, которому требуется небольшой фрагмент JS, чтобы кнопки закрытия сообщений работали. Однако сообщения клонируются из тега шаблона HTML с использованием document.importNode в библиотеке. Это означало, что даже если я прикреплю обработчики событий к шаблону в новом HTML, они будут потеряны во время клонирования.

Я не могу сделать Тим вариант 1, просто повторно присоединить их во время клонирования, так как библиотека сообщений не зависит от инфраструктуры интерфейса. (Интересно, что мой предыдущий интерфейс был в Zurb Foundation, который использует атрибут "закрываемость данных", функциональность которого действительно выживает в процессе клонирования).

Предложенная обычная обработка событий была такой:

$('.message .close').on('click', function() {
    $(this)
    .closest('.message')
    .transition('fade');
});

Проблема заключается в том, что ".message" при загрузке приложения соответствует только одному шаблону, а не фактическим сообщениям, которые приходят позже через веб-сокеты.

Делать это делегированным, означало присоединение события к контейнеру, в который клонируются сообщения <div id="user-messages">

Так и становится:

$('#user-messages').on('click', '.message .close', function() {
    $(this)
    .closest('.message')
    .transition('fade');
});

Это сработало сразу, сохранив любую сложную работу, например, третий вариант переноса событий.

Эквивалент Dojo выглядит довольно схожим по концепции.

Ответ 3

Это не дает точного ответа на вопрос, но если вариант использования позволяет перемещать элемент, а не копировать его, вы можете использовать removeChild вместе с appendChild, который сохранит прослушиватели событий. Например:

function relocateElementBySelector(elementSelector, destSelector) {
  let element = document.querySelector(elementSelector);
  let elementParent = element.parentElement;
  let destElement = document.querySelector(destSelector);
  elementParent.removeChild(element);
  destElement.appendChild(element);
}