所以我用 .bind() 调用了一个函数,但稍后在我的代码中我必须删除那个 eventListner。
EventTarget.addEventListener("click", myFunction.bind(null, arg))
所以我用 .bind() 调用了一个函数,但稍后在我的代码中我必须删除那个 eventListner。
EventTarget.addEventListener("click", myFunction.bind(null, arg))
可以通过元素的引用本身将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>
如果选择使用AbortController
和AbortSignal
Web 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>
没有理由在这个用例中使用 .bind ,而是使用现代AbortController 信号:
const controller = new AbortController();
EventTarget.addEventListener(
`click`,
() => blah.handler(arg),
{
signal: controller.signal
}
);
然后每当您需要清理该事件侦听器时:
controller.abort();
并做了。JS 引擎将知道该做什么,不需要使用与 addEventListener 相同的参数的 removeEventListener。