如何使用事件侦听器复制 DOM 节点?

IT技术 javascript dom dojo
2021-02-24 18:43:53

我试过

node.cloneNode(true); // deep copy

它似乎没有复制我使用node.addEventListener("click", someFunc);.

我们使用 Dojo 库。

4个回答

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

  • 手动将所有事件侦听器添加到您的克隆节点
  • 重构您的代码以使用事件委托,以便所有事件处理程序都附加到包含原始和克隆的节点
  • 使用包装函数Node.addEventListener()来跟踪添加到每个节点的侦听器。例如,这就是 jQuery 的clone()方法能够复制节点及其事件侦听器的方式。
人们通常使用不好的做法,因为它们更方便,但并不能使它们变好。
2021-04-20 18:43:53
@jeromej 这并不总是一个坏习惯:有些用例将 JS 与 HTML 分开是不可取的,即<b onclick="this.nextElementSibling.innerHTML+='X'"><div></div>如果你将它分开,由 AJAX 加载意味着竞争风险(和意外的复杂性)。出于扩展的原因,分离是好的,但有些代码可以通过设计进行密封。内容属性和 IDL 属性都存在是有原因的。
2021-04-20 18:43:53
@RoelofCoertze - 您必须首先知道添加了哪些事件侦听器,并且还必须在完成克隆的代码位置访问,以再次分配回调,因为根据克隆的位置访问回调可能会很棘手发生在代码中,所以例子太多了,因为场景太多了。
2021-04-26 18:43:53
当坏习惯(例如 内联 javascript onclick)比适当的香草替代品更方便时,您不讨厌它吗?叹...
2021-04-30 18:43:53
您是否有一个代码示例,说明如何将事件侦听器添加到克隆代码中?
2021-05-14 18:43:53

这并不能准确回答问题,但是如果用例允许移动元素而不是复制它,您可以将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);
}
这正是我需要做的 - 很高兴知道我的用例实际上更简单。谢谢你,谢谢你,谢谢你!:)
2021-04-28 18:43:53
PS 看起来这removeChild()一步是不必要的。
2021-04-28 18:43:53

事件委托示例。

阅读 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');
});

这立即起作用,节省了任何复杂的工作,例如包装事件子的第三个选项。

道场相当于看起来在概念上非常相似。

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

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

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

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

这也称为内容属性,它独立于IDL 属性
2021-05-15 18:43:53