Skip to content

在JavaScript中添加或移除事件监听器

添加事件监听器

要向元素添加事件监听器,可以使用EventTarget.addEventListener()方法。然而,在某些情况下,为每个元素添加监听器可能会对性能产生一定的影响。在这些情况下,可以使用事件委托将单个事件监听器添加到父元素,然后检查事件目标是否与所需目标匹配。

实现一个可重用的函数on,支持事件委托并不是很复杂。除了元素、事件和回调函数之外,我们还需要向函数传递一个选项对象。

该对象将包含一个target属性,用于检查事件目标是否与指定的目标匹配。如果匹配,我们将通过提供正确的this上下文来调用回调函数。如果没有提供target值,事件监听器将被添加到元素本身。

此外,EventTarget.addEventListener()期望一个可选的options对象,我们可以将其嵌套在自己的选项对象中。这将允许我们进一步自定义事件监听器的行为。

const on = (el, evt, fn, opts = {}) => {
  const delegatorFn = e =>
    e.target.matches(opts.target) && fn.call(e.target, e);
  el.addEventListener(
    evt,
    opts.target ? delegatorFn : fn,
    opts.options || false
  );
  if (opts.target) return delegatorFn;
};

const fn = () => console.log('!');

on(document.body, 'click', fn);
// 在点击`body`元素时输出'!'

on(document.body, 'click', fn, { target: 'p' });
// 在点击`body`元素的`p`子元素时输出'!'

on(document.body, 'click', fn, { options: true });
// 在点击`body`元素时记录'!',但使用捕获而不是冒泡

on(document.body, 'click', fn, { target: 'p', options: { once: true} });
// 在点击`body`元素的`p`子元素时记录'!',但只记录一次

移除事件监听器

从元素中移除事件监听器与添加事件监听器一样简单,甚至更简单。您可以使用EventTarget.removeEventListener()方法从元素中移除事件监听器

定义一个可重用的函数off来移除监听器非常简单。我们唯一需要关注的是保持函数签名与添加事件监听器时一致。这意味着我们需要将相同的参数传递给函数。

我们之前定义的on函数的一个关键元素是它返回一个对自定义委托函数的引用。这意味着我们可以使用返回的值通过我们的新函数来移除事件监听器。

const off = (el, evt, fn, opts = false) =>
  el.removeEventListener(evt, fn, opts);

const fn = () => console.log('!');

document.body.addEventListener('click', fn);
off(document.body, 'click', fn);
// 在页面上点击时不再记录'!'

const delegatorFn =
  on(document.body, 'click', fn, { target: 'p' });
off(document.body, 'click', delegatorFn);
// 在点击`body`元素的`p`子元素时不再记录'!'

```javascript
const delegatorFnCapturing =
  on(document.body, 'click', fn, { options: true });
off(document.body, 'click', delegatorFnCapturing, { options: true });
// 点击页面后不再输出 '!' 
//   (捕获而不是冒泡的示例)

注意

这些函数的编写方式在某种程度上模仿了jQuery的onoff方法。它们并不是作为替代品,而是一种在项目中使用类似语法的方式,而无需包含jQuery。