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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15408394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:41:26  来源:igfitidea点击:

How to copy a DOM node with event listeners?

javascriptdomdojo

提问by Chakradar Raju

I tried

我试过

node.cloneNode(true); // deep copy

It doesn't seem to copy the event listeners that I added using node.addEventListener("click", someFunc);.

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

We use the Dojo library.

我们使用 Dojo 库。

回答by Tim Down

cloneNode()does not copy event listeners. In fact, there's no way of getting hold of event listeners via the DOM once they've been attached, so your options are:

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

  • Add all the event listeners manually to your cloned node
  • Refactor your code to use event delegation so that all event handlers are attached to a node that contains both the original and the clone
  • Use a wrapper function around Node.addEventListener()to keep track of listeners added to each node. This is how jQuery's clone()method is able to copy a node with its event listeners, for example.
  • 手动将所有事件侦听器添加到您的克隆节点
  • 重构您的代码以使用事件委托,以便所有事件处理程序都附加到包含原始和克隆的节点
  • 使用包装函数Node.addEventListener()来跟踪添加到每个节点的侦听器。例如,这就是 jQuery 的clone()方法能够复制节点及其事件侦听器的方式。

回答by scipilot

Event Delegation example.

事件委托示例。

After reading Tim Down's answer, I found delegated events are very easy to implement, solving a similar problem I had. I thought I would add a concrete example, although it's in JQuery not Dojo.

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

I am re-skining an application in Semantic UI, which requires a small piece of JS to make the message close buttons work. However the messages are cloned from an HTML template tag using document.importNodein a library. This meant even if I did attach the event handlers to the template in the new HTML, they are lost during the cloning.

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

I cannot do Tim's option 1, to simply re-attach them during cloning as the messaging library is front-end framework agnostic. (Interestingly my previous front-end was in Zurb Foundation which uses a "data-closable" attribute, the functionality of which does survive the cloning process).

我不能做 Tim 的选项 1,在克隆期间简单地重新附加它们,因为消息传递库是前端框架不可知的。(有趣的是,我之前的前端是在 Zurb Foundation 中,它使用“数据可关闭”属性,其功能在克隆过程中仍然存在)。

The normal event handling suggested was like this:

建议正常事件处理是这样的

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

The problem being ".message" at app-load only matches the single template, not the actual messages which arrive later over web-sockets.

问题是应用程序加载时的“.message”只匹配单个模板,而不是稍后通过网络套接字到达的实际消息。

Making this delegated, meant attaching the event to the container into which the messages get cloned <div id="user-messages">

委托这意味着将事件附加到消息被克隆到的容器 <div id="user-messages">

So it becomes:

所以就变成了:

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

This worked immediately, saving any complex work like the third option of wrapping the event subs.

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

The Dojo equivalentlooks pretty similar in concept.

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

回答by Trade-Ideas Philip

This is what @JeromeJwas describing in a comment. Create the initial element using this HTML code.

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

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

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

When you clone this element the result will have the same handler, and "this" will point to the cloned element.

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

It would be great if the ONCLICK handler could easily be added in JavaScript. This approach means that you have to write some of your code in HTML.

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

回答by Richard Greenwood

This does not answer the question exactly, but if the use case allows for movingthe element rather than copyingit, you can use removeChildtogether with appendChildwhich will preserve the event listeners. For example:

这并不能准确回答问题,但是如果用例允许移动元素而不是复制它,您可以将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);
}