0

所以我用 .bind() 调用了一个函数,但稍后在我的代码中我必须删除那个 eventListner。

EventTarget.addEventListener("click", myFunction.bind(null, arg))

4

2 回答 2

1

可以通过元素的引用本身将set每个元素特定的绑定处理函数存储在/到 aWeakMap中,因此可以轻松地get再次检索它,例如取消注册它。

function logEventWithBoundHandlerId({ type, currentTarget }) {
  console.log({ type, currentTarget, bounId: this.id });
}
const handlerStorage = new WeakMap;

function registerAnyBoundHandler({ currentTarget }) {
  document
    .querySelectorAll('div button')
    .forEach((elm, idx) => {

      // create bound handler.
      const handler = logEventWithBoundHandlerId.bind({ id: idx + 1 });

      // add bound handler to storage (weak map)
      // by element reference.
      handlerStorage.set(elm, handler);

      // add listener.
      elm.addEventListener('click', handler);
    });
  currentTarget.parentNode.querySelector('[disabled]').disabled = false;
  currentTarget.disabled = true;
}
function unregisterAnyBoundHandler({ currentTarget }) {
  console.clear();

  document
    .querySelectorAll('div button')
    .forEach(elm => {

      // remove listener.
      elm.removeEventListener('click', handlerStorage.get(elm));

      // delete bound handler from storage (weak map)
      // by element reference.
      handlerStorage.delete(elm);
    });
  currentTarget.parentNode.querySelector('[disabled]').disabled = false;
  currentTarget.disabled = true;
}

function init() {
  const [ btnRegister, btnUnregister ] = document
    .querySelectorAll('fieldset button');

  btnRegister.addEventListener('click', registerAnyBoundHandler);
  btnUnregister.addEventListener('click', unregisterAnyBoundHandler);
}
init();
body { margin: 0; }
fieldset { margin: 0 0 5px 0; padding: 5px 3px; }
div { padding-left: 4px; }
.as-console-wrapper { max-height: 65%!important; top: auto; }
<fieldset>
  <button>register any bound handler</button>
  <button disabled>unregister any bound handler</button>
</fieldset>

<div>
  <button>click 1</button>
  <button>click 2</button>
  <button>click 3</button>
</div>

如果选择使用AbortControllerAbortSignalWeb API,则必须遵循相同的存储方法。

function logEventWithBoundHandlerId({ type, currentTarget }) {
  console.log({ type, currentTarget, bounId: this.id });
}
const controllerStorage = new WeakMap;

function registerAnyBoundHandler({ currentTarget }) {
  document
    .querySelectorAll('div button')
    .forEach((elm, idx) => {

      // create element specific abort controller.
      const controller = new AbortController;

      // add element specific controller to storage
      // (weak map) by the very element's reference.
      controllerStorage.set(elm, controller);

      // add listener with the `signal` option.
      elm.addEventListener(
        'click',
        logEventWithBoundHandlerId.bind({ id: idx + 1 }),
        { signal: controller.signal },
      );
    });
  currentTarget.parentNode.querySelector('[disabled]').disabled = false;
  currentTarget.disabled = true;
}
function unregisterAnyBoundHandler({ currentTarget }) {
  console.clear();

  document
    .querySelectorAll('div button')
    .forEach(elm => {

      // retrieve element specific controller.
      const controller = controllerStorage.get(elm);
      // abort controller.
      controller.abort();

      // delete element specific controller from
      // storage (weak map) by element reference.
      controllerStorage.delete(elm);
    });
  currentTarget.parentNode.querySelector('[disabled]').disabled = false;
  currentTarget.disabled = true;
}

function init() {
  const [ btnRegister, btnUnregister ] = document
    .querySelectorAll('fieldset button');

  btnRegister.addEventListener('click', registerAnyBoundHandler);
  btnUnregister.addEventListener('click', unregisterAnyBoundHandler);
}
init();
body { margin: 0; }
fieldset { margin: 0 0 5px 0; padding: 5px 3px; }
div { padding-left: 4px; }
.as-console-wrapper { max-height: 65%!important; top: auto; }
<fieldset>
  <button>register any bound handler</button>
  <button disabled>unregister any bound handler</button>
</fieldset>

<div>
  <button>click 1</button>
  <button>click 2</button>
  <button>click 3</button>
</div>

于 2022-01-10T02:42:03.797 回答
0

没有理由在这个用例中使用 .bind ,而是使用现代AbortController 信号

const controller = new AbortController();

EventTarget.addEventListener(
  `click`,
  () => blah.handler(arg),
  {
    signal: controller.signal
  }
);

然后每当您需要清理该事件侦听器时:

controller.abort();

并做了。JS 引擎将知道该做什么,不需要使用与 addEventListener 相同的参数的 removeEventListener。

于 2022-01-09T22:24:24.547 回答