对象字面量中的 removeEventListener

removeEventListener in object literal

我正在努力处理对象文字中的 removeEventListener。 我有一个对象,当用户在网站上使用 tab 键时,它处理添加和删除自定义大纲。

const OUTLINE = {
  enableOutline: function () {
    if (event.key === 'Tab' || (event.shiftKey && event.key === 'Tab')) {
      document.addEventListener('focusin', () => this.showOutline());
    }
  },
  showOutline: function () {
    this.showLogoOutline(event);
  },
  showLogoOutline: function () {
    if (event.target === this.logo) {
      this.logo.classList.add('logo_outline');
    }
  }
};

document.addEventListener('keydown', () => OUTLINE.enableOutline(event));

同一对象包含删除轮廓的方法,但未成功尝试删除 EventListener

const OUTLINE = {
  hideOutline: function () {
    this.hideLogoOutline();
    // BELOW DOESN'T WORK
    document.removeEventListener('focusin', this.showOutline);
  },
  hideLogoOutline: function () {
    if (this.logo.classList.contains('logo_outline')) {
      this.logo.classList.remove('logo_outline');
    }
  }
};

document.addEventListener('mousedown', () => OUTLINE.hideOutline());

正如 @Mike 'Pomax' Kamermans 在评论中提到的,每次您说 () => aFunction(),您都在创建一个全新的函数。只需传入 aFunction.

之类的原始函数

您似乎也没有正确传递 event 变量,我已经在下面的代码块中修复了这个问题。

const OUTLINE = {
  enableOutline: function (event) {
    if (event.key === 'Tab' || (event.shiftKey && event.key === 'Tab')) {
      document.addEventListener('focusin', this.showOutline);
    }
  },
  showOutline: function (event) {
    this.showLogoOutline(event);
  },
  showLogoOutline: function (event) {
    if (event.target === this.logo) {
      this.logo.classList.add('logo_outline');
    }
  },
  hideOutline: function () {
    this.hideLogoOutline();
    document.removeEventListener('focusin', this.showOutline);
  },
  hideLogoOutline: function () {
    if (this.logo.classList.contains('logo_outline')) {
      this.logo.classList.remove('logo_outline');
    }
  }
};

document.addEventListener('keydown', OUTLINE.enableOutline);

document.addEventListener('mousedown', OUTLINE.hideOutline);

首先:永远不要超载制表键(或任何在所有浏览器中具有通用行为的键)。 Tab 被浏览器用来在 tabIndexable 元素中导航,像这样的代码“捕获”了 tab 键。不酷。尤其不适合不会使用鼠标的人。 特别是如果这“只适合你”或“只适合[你认识的人不属于该类别]”,养成不超负荷的习惯内置行为,因为这样你就不会在确实重要的时候写出糟糕的代码。

话虽如此,您实际上并没有删除添加的侦听器。函数 () => OUTLINE.hideOutline() 是一个新函数,作用域为声明上下文(与使用 function() { ...} 时获得的执行上下文相反),因此指向与 [=16 完全不同的东西=] 指向.

删除侦听器时不会进行任何类型的搜索或匹配,它只能删除您之前告诉它添加的 exactly the same thing(即它必须具有相同的事件名称、相同的函数句柄和如果您指定了相同的优先级标志)。

因为这是一个单例对象原语(例如没有有意义的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();
    }
  },
};