Vanilla JS 移除柯里化函数中的事件监听器

Vanilla JS remove eventlistener in currying function

我有一个非常“简单”的 vanillaJS 问题。如何在 currying 函数内的循环中删除事件侦听器?这只是我当前解决方案的一个示例,我实际上需要多个参数传给侦听器。如果我是对的,我怀疑由于匿名回调而没有删除事件监听器?我怎样才能解决这个问题?这里的例子 https://codepen.io/shnigi/pen/wvPwqVR

const setEventListener = (buttons) => (event) => {
  const buttonValue = event.target.value;
  console.log('Eventlistener exists', buttonValue)
  buttons.forEach(button => button.removeEventListener('click', setEventListener));
};

const buttons = document.querySelectorAll('button');
buttons.forEach(button => button.addEventListener('click', setEventListener(buttons)));

// Works as expected, listener is named
const testbutton = document.getElementById('kek');
const testListener = () => {
  console.log('I show up only once');
  testbutton.removeEventListener('click', testListener);
};

testbutton.addEventListener('click', testListener);
<button value="1">press me</button>
<button value="2">press me</button>
<button id="kek">eventlistener removed on click</button>

I suspect that the event listener is not removed due to anonymous callback if I am right?

是的,这是一个问题。 所以你必须将匿名函数分配给变量并使用它来删除事件监听器。

这是给你的示例代码。

const setEventListener = (buttons: NodeList) => {
    const returnedFunc = (event: Event) => {
      const buttonValue = (event.target as HTMLButtonElement).value;
      console.log('Eventlistener exists', buttonValue)
      buttons.forEach(button => button.removeEventListener('click', returnedFunc));
    };
    return returnedFunc;
};

const buttons: Nodelist = document.querySelectorAll('button');
buttons.forEach(button => button.addEventListener('click', setEventListener(buttons)));

// Works as expected, listener is named
const testbutton = document.getElementById('kek');
const testListener = () => {
  console.log('I show up only once');
  testbutton.removeEventListener('click', testListener);
};

testbutton.addEventListener('click', testListener);

如果您不关心 Internet Explorer 支持,您可以使用 AbortController 以更优雅的方式删除匿名事件侦听器。将 signal 选项传递给 addEventListener() 并在要删除事件侦听器时调用 AbortController 的 abort() 方法:

var listenersRemover = new AbortController();
button.addEventListener('click', callback, {signal: listenersRemover.signal}));
listenersRemover.abort();

Note:您应该“重新武装”中止控制器以对新的 addEventListener() 调用使用相同的信号。只需使用 new AbortController().

再次初始化它

var listenersRemover = new AbortController();

const setEventListener = (buttons) => (event) => {
  const buttonValue = event.target.value;
  console.log('Eventlistener exists', buttonValue)
  // buttons.forEach(button => button.removeEventListener('click', setEventListener));
};

const buttons = document.querySelectorAll('button');
buttons.forEach(button => button.addEventListener('click', setEventListener(buttons), {signal: listenersRemover.signal}));

// Works as expected, listener is named
const testbutton = document.getElementById('kek');
const testListener = () => {
  console.log('I show up only once');
  //testbutton.removeEventListener('click', testListener);
  listenersRemover.abort();
};

testbutton.addEventListener('click', testListener, {signal: listenersRemover.signal});
<button value="1">press me</button>
<button value="2">press me</button>
<button id="kek">eventlistener removed on click</button>