【问题标题】:How to copy an event listener in plain Javascript如何在纯 Javascript 中复制事件侦听器
【发布时间】:2020-05-30 07:30:54
【问题描述】:

所以我正在对 Wordpress 插件进行一些覆盖。我需要在元素上复制事件侦听器,然后替换元素并将其添加回来。事件监听器由插件生成。

我认为 getEventListeners() 会起作用,但我读过它只在控制台中起作用。如果真是这样的话,我真的很震惊。我们正处于可怕的 2020 年,我没有找到明显的解决方案。

这里的解决方案是什么?

下面是我试图实现的代码,假设 getEventListeners 不仅仅是一个控制台函数。

  // Edit Affirm
  (function replaceAffirm() {
    if (document.querySelector(".affirm-modal-trigger")) {
      const learnMore = document.querySelector("#learn-more");
      const modalTrigger = document.querySelector(".affirm-modal-trigger");
      const clickHandler = getEventListeners(modalTrigger).click[0].listener;
      const substr = learnMore.innerHTML
        .toString()
        .substring(
          learnMore.innerHTML.indexOf("h") + 2,
          learnMore.innerHTML.length
        );
      learnMore.innerHTML = "Easy Financing with " + substr;
      modalTrigger.addEventListener("click", clickHandler);
    } else {
      setTimeout(function () {
        replaceAffirm();
      }, 250);
    }
  })();

HTML

<p id="learn-more" class="affirm-as-low-as" data-amount="20000" data-affirm-color="white" data-learnmore-show="true" data-page-type="product">
   Starting at 
   <span class="affirm-ala-price">$68</span>
   /mo with 
   <span class="__affirm-logo __affirm-logo-white __ligature__affirm_full_logo__ __processed">Affirm</span>. 
   <a class="affirm-modal-trigger" aria-label="Prequalify Now (opens in modal)" href="javascript:void(0)">Prequalify now</a>
</p>

【问题讨论】:

  • 据我所知,该功能仅限于 Chrome,而不仅仅是控制台。无论如何,您可以删除该元素,然后将其添加回其他地方。另外,请添加相关的HTML代码
  • 你正在做的事情似乎你在思考你的问题是错误的。你到底想用字符串操作做什么?为什么它必须每 250 毫秒发生一次?
  • 我会直接给你的。您不能在 vanilla JS 中复制事件处理程序。完全没有。这不是你可以使用的东西,因为它在 vanilla JS 中根本不可能。除非有外部引用,否则事件处理程序一旦添加就会被黑盒化。但是,可能有一种方法可以获得您想要的最终结果,您只是在寻找解决方案的错误方向。我会在 10 分钟后查看并尝试提供帮助。
  • @MichaelPaccione 从理论上讲它可能是为了安全,但更有可能它只是被设计强制进入该状态。像 JQuery 这样的几个库实现了自己的事件侦听器代理对象,以便您可以更好地管理事件。我添加了一个答案,但如果不是您想要的,请告诉我。

标签: javascript event-listener


【解决方案1】:

您无法复制事件侦听器,但似乎由于您的 HTML 结构,您更有可能不需要重新添加它。与其编辑 HTML 并删除事件侦听器,不如围绕它进行编辑。

如果您想删除文本节点,您可以遍历childNodes 并分离出应该删除的内容。

然后要在您想要的位置重建适当的文本,您可以使用insertAdjacentText

if (document.querySelector(".affirm-modal-trigger")) {
  const learnMore = document.querySelector("#learn-more");
  const modalTrigger = document.querySelector(".affirm-modal-trigger");
  const children = Array.from(learnMore.childNodes);

  children.forEach(child => {
    if (child.nodeType === Node.TEXT_NODE || child.matches(".affirm-ala-price")) {
      if (learnMore.contains(child)) {
        learnMore.removeChild(child);
      }
    }
  });

  learnMore.insertAdjacentText("afterBegin", "Easy Financing With ");
  modalTrigger.insertAdjacentText("beforeBegin", " ");
} else {
  setTimeout(function() {
    replaceAffirm();
  }, 250);
}
<p id="learn-more" class="affirm-as-low-as" data-amount="20000" data-affirm-color="white" data-learnmore-show="true" data-page-type="product">
  Starting at
  <span class="affirm-ala-price">$68</span> /mo with
  <span class="__affirm-logo __affirm-logo-white __ligature__affirm_full_logo__ __processed">Affirm</span>.
  <a class="affirm-modal-trigger" aria-label="Prequalify Now (opens in modal)" href="javascript:void(0)">Prequalify now</a>
</p>

【讨论】:

  • 插入相邻文本!!!太棒了,我不知道这个功能 :) 今晚晚些时候我将对此进行测试。替换整个 textContent 当然会删除事件监听器,所以希望这个方法只是一个插入而不是引擎盖下的替换。谢谢!
  • @MichaelPaccione 我想说的是,不幸的是,它没有应有的知名度。它非常有用:)
【解决方案2】:

是的,等待 Html 元素被加载并检查直到它被加载是可以的,这是等待它的正确方法之一。

根据我对您的问题的理解,您只需更改 learn-more 元素的文本。 为此,无需复制事件侦听器然后再次绑定它。

无需替换整个元素,只需更改保持相同元素的文本即可。 所以它默认与事件监听器绑定。

【讨论】:

  • 嗨 Minal 我已经添加了 HTML。问题是如何复制确认模式触发器上的事件侦听器,将其保存到变量中,然后将其添加回新编辑的 DOM 元素。当您重置 innerHTML 时,元素上的事件侦听器将丢失。
  • 同样使用 textContent 方法也不起作用,因为具有事件侦听器的元素位于 textContent 中。自然地用 innerHTML 替换 textContent 会移除监听器。
猜你喜欢
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 2012-09-10
  • 2020-06-15
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
相关资源
最近更新 更多