在使用addEventListener添加事件之前,请先使用removeEventListener删除事件

时间:2018-07-12 17:14:06

标签: javascript

我正在尝试使用允许订阅任何事件的常规功能。我想确保每个事件和元素都只订阅一个。因此,在添加新的事件侦听器之前,请删除之前的事件侦听器。

问题是,我使之成为上一个事件的方式没有被删除,我也不知道为什么。

遵循一个有效的示例:

function delegate(el, evt, sel, handler) {
  let eventListenerHandler = (event) => {
    var t = event.target;
      while (t && t !== this) {
          if (t.matches && t.matches(sel)) {
              handler.call(t, event);
          }
          t = t.parentNode;
      }
  }
  el.removeEventListener(evt, eventListenerHandler, evt === "focus" ? true : false);
  el.addEventListener(evt, eventListenerHandler, evt === "focus" ? true : false);
}
let consoleLog = () => console.log("WAS FOCUS");
delegate(document, "focus", "input", consoleLog);
delegate(document, "focus", "input", consoleLog);
<input/>
<input/>

在示例中可以看到,每次选择一个输入时,它都会打印两次消息“ WAS FOCUS”,而我想要的是确保只打印一个。

谢谢。

2 个答案:

答案 0 :(得分:3)

一种实现Ry在注释中建议的相对简单的方法是将处理程序函数存储在元素本身上-我在这里使用了一个对象,以便可以将不同事件类型的处理程序存储在事件名称下。 。 (您只想为每个元素的一个事件类型使用一个处理程序,对吧?)

然后,如果已经存在这样的存储处理程序,则在 之前将其删除,然后将其替换为新的处理程序。

现在不认为将这种数据直接“存储在” DOM元素上是一种好习惯;至少是因为可能与将来使用的同名指定属性发生冲突。但是在这种情况下,这是解决此问题的非常简单的方法;当然,您可以将处理程序函数存储在其他位置,但是无论如何,您仍然必须保留对DOM元素的引用,因为您还需要能够区分分配给不同元素的处理程序。

function delegate(el, evt, sel, handler) {
  el.eventListenerHandler = el.eventListenerHandler || {};
  if(el.eventListenerHandler[evt]) {
    el.removeEventListener(evt, el.eventListenerHandler[evt], evt === "focus" ? true : false);
  }
  el.eventListenerHandler[evt] = (event) => {
    var t = event.target;
      while (t && t !== this) {
          if (t.matches && t.matches(sel)) {
              handler.call(t, event);
          }
          t = t.parentNode;
      }
  }
  el.addEventListener(evt, el.eventListenerHandler[evt], evt === "focus" ? true : false);
}
let consoleLog = () => console.log("WAS FOCUS");
delegate(document, "focus", "input", consoleLog);
delegate(document, "focus", "input", consoleLog);
<input/>
<input/>

答案 1 :(得分:1)

对于removeEventListener(event,functionName),您必须提供与以前添加的功能相同的要删除功能。

现在,每个delegate(document, "focus", "input", consoleLog);在自己的作用域上创建函数eventListenerHandler并将其添加到addEventListener中。

基本上两个委托()调用会创建两个具有相同功能的不同函数eventListenerHandler

现在,如果我们可以将先前添加的eventListenerHandler保存到变量中,然后在removeEventListener中使用它,那么它将起作用。

这里是例子。

var temp = function(){};
    function delegate(el, evt, sel, handler) {
      let eventListenerHandler = (event) => {
        var t = event.target;
          while (t && t !== this) {
              if (t.matches && t.matches(sel)) {
                  handler.call(t, event);
              }
              t = t.parentNode;
          }
      }
      el.removeEventListener(evt, temp, evt === "focus" ? true : false);
      el.addEventListener(evt, eventListenerHandler, evt === "focus" ? true : false);
      temp = eventListenerHandler ;
    }
    let consoleLog = () => console.log("WAS FOCUS");
    delegate(document, "focus", "input", consoleLog,false);
    delegate(document, "focus", "input", consoleLog,false);
<input>
<input>

为更好地理解,您可以参考javascript Closure概念。

对于您的解决方案,您必须将添加为eventListener的每个函数保存为其事件和元素,并在以后使用相同事件对该元素进行调用时删除该函数。