EventTarget.removeEventListener() 取消监听事件不起作用(失效)的原因

一.问题产生的原因

没有正确匹配到要删除的事件监听

二.语法介绍

1.监听事件
addEventListener() 语法

target.addEventListener(type, listener[, options])
target.addEventListener(type, listener[, useCapture])

2.取消事件
removeEventListener() 语法

target.removeEventListener(type, listener[, options])
target.removeEventListener(type, listener[, useCapture])

参数说明

  • type: 表示监听事件类型的字符串。
  • listener: 目标事件绑定的回调函数
  • options: 一个指定有关 listener 属性的可选参数对象
  • useCapture: 指定需要移除的 EventListener 函数是否为捕获监听器。true 表示“事件捕获”, 默认为
    false, 表示“事件冒泡”

3. removeEventListener() 移除成功需要满足

  • 需要移除的事件类型必须是一样的, 比如: click

  • 需要从目标事件移除的 EventListener 函数必须和
    addEventListener 中注册的是同一个, 也就是说引用地址是相同的

  • 指定需要移除的 EventListener 函数的useCapture 和 addEventListener 中注册的相同的

4.举例说明

1、设置 useCapture

element.addEventListener("mousedown", handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false); // 失败
element.removeEventListener("mousedown", handleMouseDown, true); // 成功

2、设置 options

element.addEventListener("mousedown", handleMouseDown, {
    
     passive: true });

注意此时的 useCapture 默认为 false, 所以 removeEventListener 也应该设置 useCapture 为 false

element.removeEventListener("mousedown", handleMouseDown, {
    
     passive: true }); // 成功
element.removeEventListener("mousedown", handleMouseDown, {
    
     capture: false }); // 成功
element.removeEventListener("mousedown", handleMouseDown, {
    
     capture: true }); // 失败
element.removeEventListener("mousedown", handleMouseDown, {
    
     passive: false }); // 成功
element.removeEventListener("mousedown", handleMouseDown, false); // 成功
element.removeEventListener("mousedown", handleMouseDown, true); // 失败

三.可能遇到的问题

1.使用了匿名函数
这样写是无效的

// index.vue
create (){
    
    
  document.addEventListener( "click", function() {
    
     console.log("匿名函数, click") }, false );
},

destroyed() {
    
    
  // 这样写是无效的
  document.removeEventListener( "click", function() {
    
     console.log("匿名函数, click") }, false );
},

需要改成:

// index.vue
create (){
    
    
  document.addEventListener( "click", this.callBack, false );
  // 监听生命周期
  // this.$once('hook:destroyed', () => {
    
    
      // document.removeEventListener( "click", this.callBack, false );
  // })
},

// 也可以使用上面的方法监听生命周期
destroyed() {
    
    
  document.removeEventListener( "click", this.callBack, false );
},

methods: {
    
    
  callBack() {
    
     console.log("匿名函数, click") };
}

2.忽略了函数的引用地址
这样写是无效的

// index.vue
create (){
    
    
  this.eventListener("add");
  this.$once('hook:destroyed', () => {
    
    
     this.eventListener("remove");
  })
},

methods: {
    
    
  eventListener(val) {
    
    
    const callBackFn = () => {
    
    
      console.log("函数表达式, click");
    };
    if (val === "add") {
    
    
      document.addEventListener("click", callBackFn);
    } else if (val === "remove") {
    
    
      document.removeEventListener("click", callBackFn);
    }
  },
}

因为 create() 和 destroyed() 两次的调用分别初始化了一个函数 callBackFn, 这两个 callBackFn 存放在内存中的地址是不一样的, 是两个没有关系的函数, 所以 removeEventListener() 是不起作用(失效)的
同理改成下面这样: 把 callBackFn 提取到一个公共方法中:

// code...
methods: {
    
    
  eventListener(val) {
    
    
    if (val === "add") {
    
    
      document.addEventListener("click", this.callBackFn);
    } else if (val === "remove") {
    
    
      document.removeEventListener("click", this.callBackFn);
    }
  },

  callBackFn() {
    
    
    console.log("函数表达式, click");
  }
}

归根结底的原因是: 没有正确匹配到要删除的事件监听

猜你喜欢

转载自blog.csdn.net/xiaolinlife/article/details/130765391