首先:永远不要重载 tab 键(或在所有浏览器中具有通用行为的任何键)。Tab浏览器使用它来浏览 tabIndexable 元素,并且像这样的代码会“捕获” tab 键。不酷。尤其不适合不会使用鼠标的人。特别是如果这是“只为你”或“只为[你认识的人不属于该类别]”,请养成不要重载内置行为的习惯,因为这样你就永远不会编写糟糕的代码这很重要。
话虽如此,您实际上并没有删除您添加的侦听器。该函数() => OUTLINE.hideOutline()是一个新函数,作用域为声明上下文(与您使用时获得的执行上下文相反function() { ...}),因此指向与指向完全不同的事物OUTLINE.hideOutline。
删除侦听器时没有任何类型的搜索或匹配,它只能删除您之前告诉它添加的完全相同的东西(即,如果您指定,它必须具有相同的事件名称、相同的函数句柄和相同的优先级标志一)。
由于这是一个单例对象原语(例如没有意义的this),所以不要使用this,直接用它的const名字来引用自己,这样就可以通过直接引用来添加和删除它的功能:
const OUTLINE = {
...
enableOutline: function(event) {
const { key } = event;
if (key.toLowerCase() === `f`) {
document.addEventListener('focusin', OUTLINE.showOutline);
}
}
hideOutline: function(_event) {
document.removeEventListener('focusin', OUTLINE.showOutline);
},
};
但是当然,如果您要设置一个需要大量添加和删除事件侦听器的设置,请编写一个简单的事件管理器。例如,从这样的东西开始,并根据需要对其进行自定义。
class EventManager {
constructor() {
this.events = {};
}
listen(target, evtName, handler) {
if (!this.events[evtName]) this.events[evtName] = [];
const evtList= this.events[evtName];
const position = this.events[evtName].length;
const entry = { target, handler, removed:false, remove: () => {
// removeEventListener always returns undefined
evtList[position] = target.removeEventListener(evtName, handler);
entry.removed = true;
}});
target.addEventListener(evtName, handler);
this.events[evtName].push(entry);
return entry;
}
forget(target, evtName, handler=false) {
const evtList = this.events[evtName];
evtList
.filter(e => (e.target===target && (handler ? e.handler===handler : true)))
.forEach(e => e.remove())
}
}
const Events = new EventManager();
export default Events
这会将你的代码变成这样的东西:
import Events from "globalManager";
const OUTLINE = {
...
enableOutline: function(event) {
const { key } = event;
if (key.toLowerCase() === `f` && !OUTLINE.listener) {
OUTLINE.listener = Events.listen(document, `focusin`, OUTLINE.showOutline);
}
}
hideOutline: function() {
if (OUTLINE.listener) {
OUTLINE.listener = OUTLINE.listener.remove();
}
},
};