Как скопировать DOM node с прослушивателями событий?
Я пробовал
node.cloneNode(true); // deep copy
Кажется, он не копирует прослушиватели событий, которые я добавил с помощью node.addEventListener("click", someFunc);
.
Мы используем библиотеку Dojo.
Ответы
Ответ 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);
}