← 返回目录

12. 事件委托原理与实战

事件委托就像前台统一代收快递:不是让每栋楼、每个人自己跑下楼(每个小元素绑事件),而是只让前台(父元素)一个人收。点哪个小元素,它的事件会"冒泡"传到前台,前台用 e.target 一看快递单"这是谁的",再办事。好处:少绑事件、以后新来的人也自动有快递可收

12.1 互动演示(只给 ul 绑一次,新来的也能用)

先点现有菜单项,再点"加一个",然后点新菜单——它没重新绑也能响应。

12.2 知识点逐条讲解

① 笨办法 vs 聪明办法

// ❌ 笨办法:每个 li 都绑一次
let lis = document.querySelectorAll('#menu li'); // 先找出所有 li
lis.forEach(li => li.addEventListener('click', show)); // 挨个给每个 li 绑事件
// 问题:以后新加的 li 没绑上,还得再绑一遍,浪费

// ✅ 聪明办法:只给爹 ul 绑一次
let ul = document.getElementById('menu'); // 只抓到爹 ul
ul.addEventListener('click', function (e) { // 点 ul 里任何东西都会冒泡到这
  if (e.target.nodeName === 'LI') {   // 看快递单:点中的是不是 li
    console.log(e.target.innerText); // 是 li,就把它的字打出来
  }
});
	

② 核心三步

① 事件会冒泡:点 li,一路冒到爹 ul;② 爹只绑了一个监听;③ 在监听里用 e.target 看一眼"点的是不是 li",是才办事。

如果你忘了判断 e.target 是不是 li 就直接办事,可能点到空白处也触发。因为 ul 里除了 li 还有空格、padding 这些;所以要先看 nodeName === 'LI'(或用 matches)。

③ 为什么新元素自动能用

因为监听绑在爹 ul 上,新 li 再怎么加,都是 ul 的孩子,点它照样冒泡到 ul——根本不用重新绑。这就是委托最大的好处。

实战:用在哪 / 常见坑 / 怎么解决

① 用在哪:聊天消息、商品列表、待办项等动态生成的列表点击。

② 常见坑:忘了判断 e.target 是不是目标标签,点空白也触发;新元素忘了绑定。

③ 怎么解决:给父绑一次,用 e.target.matches()/nodeName 判断;新元素自动生效不用重绑。

一句话记住:给爹绑一次,靠冒泡把事件传上来,用 e.target 判断点中的是不是目标;少绑事件,新来的元素自动能用。