【问题标题】:How to copy a DOM node with event listeners?如何使用事件监听器复制 DOM 节点?
【发布时间】:2013-03-02 18:00:17
【问题描述】:

我试过了

node.cloneNode(true); // deep copy

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

我们使用 Dojo 库。

【问题讨论】:

    标签: javascript dom dojo


    【解决方案1】:

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

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

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

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

    【讨论】:

    【解决方案2】:

    这并不能完全回答问题,但如果用例允许移动元素而不是复制它,您可以将removeChild与@987654322一起使用@ 将保留事件侦听器。例如:

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

    【讨论】:

    • 这正是我需要做的——很高兴知道我的用例实际上更简单。谢谢你,谢谢你,谢谢你! :)
    • P.S.看起来 removeChild() 步骤是不必要的。
    【解决方案3】:

    事件委托示例。

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

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

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

    normal event handling suggested was like this:

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

    应用加载时的“.message”问题仅匹配单个模板,而不是稍后通过 web-sockets 到达的实际消息。

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

    这样就变成了:

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

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

    Dojo equivalent 在概念上看起来非常相似。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 当坏习惯(如onclick 等内联javascript)比适当的香草替代品更方便时,你不讨厌它吗?叹息……
      • 人们通常会使用不好的做法,因为它们更方便,但并不能使它们变得更好。
      • 您是否有代码示例如何将事件侦听器添加到克隆的代码中?
      • @RoelofCoertze - 您必须知道首先添加了哪些事件侦听器,并且还可以访问您已完成克隆的代码位置,以便再次分配回调,因为访问回调可能会很棘手,具体取决于代码中发生克隆的位置,因此由于场景太多,因此示例将毫无用处。
      • @jeromej 这并不总是一个坏习惯:有些用例将 JS 与 HTML 分离是不可取的,即 AJAX 加载的 <b onclick="this.nextElementSibling.innerHTML+='X'"><div></div> 如果将其分离,则意味着竞争风险(和意外的复杂性)。出于扩展原因,分离是好的,但某些代码可以通过设计密封。内容属性和 IDL 属性都存在是有原因的。
      猜你喜欢
      • 1970-01-01
      • 2021-06-04
      • 2015-01-23
      • 1970-01-01
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多