1

removeEventListener在对象文字中苦苦挣扎。我有一个对象,它处理当用户在网站上切换时添加和删除自定义轮廓。

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());
4

2 回答 2

1

首先:永远不要重载 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();
    }
  },
};
于 2021-06-13T17:20:48.183 回答
0

正如@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);
于 2021-06-13T17:20:27.993 回答