73

我试过

node.cloneNode(true); // deep copy

它似乎没有复制我使用添加的事件侦听器node.addEventListener("click", someFunc);

我们使用 Dojo 库。

4

5 回答 5

90

cloneNode()不复制事件侦听器。实际上,一旦附加了事件侦听器,就无法通过 DOM 获取它们,因此您的选择是:

  • 手动将所有事件侦听器添加到克隆节点
  • 重构代码以使用事件委托,以便所有事件处理程序都附加到包含原始和克隆的节点
  • 使用包装函数Node.addEventListener()来跟踪添加到每个节点的侦听器。例如,这就是 jQuery 的clone()方法能够使用其事件侦听器复制节点的方式。
于 2013-03-14T14:12:30.613 回答
6

这并不能准确回答问题,但如果用例允许移动元素而不是复制元素,则可以将removeChildappendChild一起使用,这将保留事件侦听器。例如:

function relocateElementBySelector(elementSelector, destSelector) {
  let element = document.querySelector(elementSelector);
  let elementParent = element.parentElement;
  let destElement = document.querySelector(destSelector);
  elementParent.removeChild(element);
  destElement.appendChild(element);
}
于 2019-04-22T19:25:12.643 回答
2

事件委托示例。

在阅读了 Tim Down 的回答后,我发现委托事件很容易实现,解决了我遇到的类似问题。我想我会添加一个具体的例子,尽管它是在 JQuery 而不是 Dojo 中。

我正在重新设计语义 UI 中的应用程序,这需要一小块 JS 才能使消息关闭按钮起作用。但是,消息是从document.importNode库中使用的 HTML 模板标签中克隆出来的。这意味着即使我确实将事件处理程序附加到新 HTML 中的模板,它们也会在克隆过程中丢失。

我无法执行 Tim 的选项 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 等效项在概念上看起来非常相似。

于 2018-11-04T03:09:26.937 回答
1

这就是@JeromeJ在评论中所描述的。使用此 HTML 代码创建初始元素。

<DIV ONCLICK="doSomething(this)">touch me</DIV>

当您克隆此元素时,结果将具有相同的处理程序,并且“this”将指向克隆的元素。

如果可以在 JavaScript 中轻松添加 ONCLICK 处理程序,那就太好了。这种方法意味着您必须用 HTML 编写一些代码。

于 2019-05-28T14:45:18.067 回答
0

我知道我迟到了,但这是一个对我有用的解决方案:

const originalButtons = original.querySelectorAll<HTMLElement>('button');
const cloneButtons = clone.querySelectorAll<HTMLElement>('button');
originalButtons.forEach((originalButton: HTMLElement, index: number) => {
  cloneButtons[index].after(originalButton);
  cloneButtons[index].remove();
});
于 2022-01-28T12:45:18.223 回答