【问题标题】:Unable to remove event listener from document无法从文档中删除事件侦听器
【发布时间】:2020-11-13 21:20:41
【问题描述】:

我有一个按钮。单击此按钮时,我会做两件事

  1. 打开搜索菜单
  2. 将事件侦听器附加到文档正文以侦听关闭事件。

但是,我似乎无法从关闭函数的文档中删除事件监听器。也就是我第二次尝试打开菜单时,它立即调用了关闭函数

我的问题是……

如何删除文档事件监听器? 以及如何做到这一点,如果用户点击搜索菜单,它不会触发文档点击事件

openDesktopSearchMenu() {
    this.$desktopSearchMenu.style.height = '330px';
    document.addEventListener('click', this.closeDesktopSearchMenu.bind(this), true);
}

closeDesktopSearchMenu() {
    this.$desktopSearchMenu.style.height = '0px';
    document.removeEventListener('click', this.closeDesktopSearchMenu.bind(this), true);
}

7 月 24 日更新 尼克的回答绝对让我朝着正确的方向前进。但是,由于捕获参数,文档总是首先被调用。因此,如果用户在搜索菜单内点击,它会自动关闭。

删除捕获参数会导致关闭函数在打开后立即被调用。

对我有用的解决方法是在我添加监听器时将其包装在超时内。然后自然我不得不在搜索菜单点击时调用 stopPropagation()

searchMenuClick = (e) => {
    e.stopPropagation();
}

/** open the desktop search menu */
openDesktopSearchMenu = () => {
    this.$desktopSearchMenu.style.height = '330px';
    this.$navBar.classList.add('search');
    setTimeout(() => {
        document.addEventListener('click', this.closeDesktopSearchMenu, { capture: false });
    });
}

closeDesktopSearchMenu = () => {
    this.$desktopSearchMenu.style.height = '0px';
    setTimeout(() => {
        this.$navBar.classList.remove('search');
    }, 300);
    document.removeEventListener('click', this.closeDesktopSearchMenu, { capture: false });
}

【问题讨论】:

    标签: javascript html ecmascript-6


    【解决方案1】:

    .bind() 方法返回一个新函数,因此您作为回调添加到 addEventListener 的函数与您尝试删除的函数的引用不同。因此,事件侦听器不会被删除。

    您可以像这样考虑在构造函数中进行绑定:

    constructor() {
      ...
      this.closeDesktopSearchMenu = this.closeDesktopSearchMenu.bind(this);
      ...
    }
    

    然后像这样使用你的方法(没有绑定,因为现在在构造函数中完成了):

    openDesktopSearchMenu() {
        this.$desktopSearchMenu.style.height = '330px';
        document.addEventListener('click', this.closeDesktopSearchMenu, true);
    }
    
    closeDesktopSearchMenu() {
        this.$desktopSearchMenu.style.height = '0px';
        document.removeEventListener('click', this.closeDesktopSearchMen, true);
    }
    

    参见下面的示例 sn-p:

    class Test {
      constructor() {
        this.prop = "bar";
        this.foo = this.foo.bind(this);
      }
      
      foo() {
        console.log('Foo', this.prop);
      }
      
      a() {
        document.addEventListener('click', this.foo, true);
      }
      
      b() {
        document.removeEventListener('click', this.foo, true);
      }
    }
    
    const test = new Test();
    console.log("Event listener added");
    test.a();
    
    setTimeout(() => {
      console.log("Event listener removed");
      test.b();
    }, 3000);

    【讨论】:

    • 有没有办法在不使用'true'参数的情况下解决这个问题?原因是因为我正在侦听搜索菜单上的事件,但是当我在搜索菜单中单击时首先调用文档事件侦听器,并自动关闭它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 2023-02-04
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2018-07-15
    • 2022-08-03
    相关资源
    最近更新 更多