Вы можете НЕ напрямую использовать функцию стрелки или любую анонимную функцию и ожидать, что сможете удалить слушателя.
Для удаления слушателя необходимо передать ТОЧНО ЖЕ АРГУМЕНТОВ removeEventListener
, как вы передали addEventListener
, но когда вы используете анонимную функцию или функцию стрелки, у вас нет доступа к этой функции так что вы не можете передать его в removeEventListener
работает
const anonFunc = () => { console.log("hello"); }
someElem.addEventListener('click', anonFunc);
someElem.removeEventListener('click', anonFunc); // same arguments
не работает
someElem.addEventListener('click', () => { console.log("hello"); });
someElem.removeEventListener('click', ???) // you don't have a reference
// to the anon function so you
// can't pass the correct arguments
// to remove the listener
ваш выбор
- не использовать анонимные функции или функции стрелок
- используйте оболочки, которые будут отслеживать аргументы за вас
Один из примеров - закрытие @Intervalia. Он отслеживает функцию и другие переданные вами аргументы и возвращает функцию, которую вы можете использовать при удалении слушателя.
Одним из решений, которое я часто использую и которое часто соответствует моим потребностям, является класс, который отслеживает всех слушателей и удаляет их всех. Вместо замыкания он возвращает идентификатор, но он также позволяет просто удалить всех слушателей, которые я нахожу полезными, когда я что-то собираю сейчас и хочу что-то разорвать позже
function ListenerManager() {
let listeners = {};
let nextId = 1;
// Returns an id for the listener. This is easier IMO than
// the normal remove listener which requires the same arguments as addListener
this.on = (elem, ...args) => {
(elem.addEventListener || elem.on || elem.addListener).call(elem, ...args);
const id = nextId++;
listeners[id] = {
elem: elem,
args: args,
};
if (args.length < 2) {
throw new Error('too few args');
}
return id;
};
this.remove = (id) => {
const listener = listeners[id];
if (listener) {
delete listener[id];
const elem = listener.elem;
(elem.removeEventListener || elem.removeListener).call(elem, ...listener.args);
}
};
this.removeAll = () => {
const old = listeners;
listeners = {};
Object.keys(old).forEach((id) => {
const listener = old[id];
if (listener.args < 2) {
throw new Error('too few args');
}
const elem = listener.elem;
(elem.removeEventListener || elem.removeListener).call(elem, ...listener.args);
});
};
}
Использование будет что-то вроде
const lm = new ListenerManager();
lm.on(saveElem, 'click', handleSave);
lm.on(newElem, 'click', handleNew);
lm.on(plusElem, 'ciick', handlePlusOne);
const id = lm.on(rangeElem, 'input', handleRangeChange);
lm.remove(id); // remove the input event on rangeElem
lm.removeAll(); // remove events on all elements managed by this ListenerManager
обратите внимание, что приведенный выше код - ES6 и должен быть изменен для поддержки действительно старых браузеров, но идеи те же.