JavaScript 之 事件委托

125 阅读3分钟

事件

事件是在编程时系统内发生的动作或者发生的事件,系统响应事件后,如果需要,您可以某种方式对事件作出回应。例如:如果用户在网页上单击一个按钮,你可能想通过显示一个信息框来响应这个动作。

事件处理器

每个可用的事件都会有一个事件处理器,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器。注意事件处理器有时候也被叫做事件监听器————从我们的用意来看两个名字是相同的,尽管严格的来说这块代码即监听也处理事件。监听器留意事件是否发生,然后处理器就是对事件发生做出的回应。

<button>Change Color</button>

js

const ndBtn = document.querySelector('button');
function random(number) {
  return Math.floor(Math.random() * (number + 1));
}
btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

事件冒泡和捕捉

当一个事件发生在具有父元素的元素上时,现代浏览器运行两个不同的阶段--捕获阶段和冒泡阶段。

在捕获阶段:

  • 浏览器检察元素的最外层祖先<html> , 是否在捕获阶段中注册了一个onclick 事件处理程序,如果是,则运行它。
  • 然后,它移动到<html> 中,淡季元素的下一个祖先元素,并执行相同的操作,然后是单元元素再下一个祖先元素,以此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反:

  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick 事件处理程序,如果是,则运行它。
  • 然后它移动到下一个直接的父元素,做同样的事件,然后是下一个,等等,直到它到达<html>元素。 在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。

事件委托

又称事件代理,是JavaScript 中常用绑定事件的常用技巧。顾名思义,“事件代理”即是吧原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的植物。

事件代理的原理是DOM元素的事件冒泡。

冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,您可以将click单击事件监听器设置在父元素<ul>上,这样事件就会从列表项冒泡到其父元素<ul>上。

事件委托的特点

  1. 可以大量节省内存占用,减少事件注册,比如在ul 上处理所有li 的click 事件。
(() => {
    var ndContainer = document.getElementById('js-list');
    if (!ndContainer) {
        return;
    }

    for (let i = 0; i < 300; i++) {
        const ndItem = document.createElement('li');
        ndItem.innerText = i + 1;
        ndContainer.appendChild(ndItem);
    }

    ndContainer.addEventListener('click', function (e) {
        const target = e.target;
        if (target.tagName === 'LI') {
            alert(target.innerHTML);
        }
    });
})();

  1. 可以实现当新增子对象时,无需再次对其绑定(动态绑定事件)

使用事件委托注意事项

使用“事件委托” 时,并不是说把事件委托给的元素越靠近顶层就越好。事件冒泡的过程也需要耗时,越靠近顶层,事件的“事件传播链”越长,也就越耗时。如果DOM嵌套结构越深,事件冒泡通过大量祖先元素就会导致性能损失。