【问题标题】:Add an event listener with parameters and then remove it添加带有参数的事件监听器,然后将其移除
【发布时间】:2019-01-06 05:31:43
【问题描述】:

基本场景

以前有人问过这个问题。事实上,有人问过with nearly the same title,但请稍等片刻,我认为这个问题还没有很好的答案。

所以,我们有一个事件监听器:

fancyButton.addEventListener('click', this.launchKitty, true);

然后我们有一个函数:

// assume this.setForLaunch was set somewhere
launchKitty = () => {
  if(this.setForLaunch){ // behold, this!
    console.log('farewell, feline!')
  }
}

我们有一个事件监听器和一个可以访问外部this 的函数,这很简洁。删除很容易:

fancyButton.removeEventListener('click', this.launchKitty, true);

但是如果我们不想使用this 怎么办?

参数!

如果我们不想依靠this,而是想传递addEventListener 一个参数怎么办?像这样:

fancyButton.addEventListener('click', () => {this.launchKitty(true)}, true);

还有一个稍作修改的launchKitty()

launchKitty(setForLaunch) {
  if(setForLaunch){ // now we're using a parameter!
    console.log('farewell, feline!')
  }
}

到目前为止,一切都很好。小猫推出。那么移除监听器呢?

fancyButton.removeEventListener('click', () => {this.launchKitty}, true);

不会工作。我们的() => {} 是匿名的,因此removeEventListener 不知道如何找到它。

问题

我们如何向事件监听器传递一个参数,然后再移除该事件处理程序?

请随时挑战我的任何假设。启动这只猫的方法有很多。

谢谢!

【问题讨论】:

    标签: javascript


    【解决方案1】:

    您应该将当前匿名函数存储到一个变量中,以便您以后可以使用它调用removeEventListener

    const launchKittyTrue = () => { this.launchKitty(true) };
    fancyButton.addEventListener('click', launchKittyTrue, true);
    // later:
    fancyButton.removeEventListener('click', launchKittyTrue, true);
    

    为了更加灵活,您可以考虑使用参数索引的Map,其值是绑定函数:

    const boundFns = new Map();
    function makeListener(arg) {
      if (!boundFns.has(arg)) {
        boundFns.set(arg, launchKitty.bind(undefined, arg));
      }
      return boundFns.get(arg);
    }
    function getListener(arg) {
      return boundFns.get(arg);
    }
    fancyButton.addEventListener('click', makeListener(true), true);
    // later:
    fancyButton.removeEventListener('click', getListener(true), true);
    

    【讨论】:

    • 这是一个非常有趣的解决方案,但它会受限于一组有限的参数。我的示例确实使用了setForLaunch=true(如此合法的答案),但是如果setForLaunch='french-fry' 或任何其他字符串也有效呢?
    • Map 解决方案会解决这个问题 - 无论其类型如何,它都可以与任何单个参数一起正常工作。额外的参数会很痛苦,我想Maps 的递归集是可能的
    • 如果所有参数都是原语,你也可以使用JSON.stringify/parse而不是递归。
    【解决方案2】:

    或者@CertainPerformance 的回答。您可以使用 Function 原型中的 bind 方法来实例化带有绑定参数的函数的“副本”。

    类似:

    function launchKitty(setForLaunch) {
      console.log(`launchKitty called with setForLaunch = ${setForLaunch}`);
    }
    
    let fancyTrue = launchKitty.bind(null, true);
    let fancyFalse = launchKitty.bind(null, false);
    
    let fancyButton = document.getElementById('fancyButton');
    let lessFancyButton = document.getElementById('lessFancyButton');
    let detachButton =  document.getElementById('detachFancyButton');
    
    fancyButton.addEventListener('click', fancyTrue, true);
    
    lessFancyButton.addEventListener('click', fancyFalse, true);
    
    
    detachButton.addEventListener('click', () => {
      fancyButton.removeEventListener('click', fancyTrue, true);
      lessFancyButton.removeEventListener('click', fancyFalse, true);
    });
    <button id='fancyButton'>Console Log</button>
    <button id='lessFancyButton'>No Console Log</button>
    
    <button id='detachFancyButton'>Detach Handlers</button>

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 2019-07-22
      相关资源
      最近更新 更多