Appearance
目录
1. 核心原理:事件冒泡
当你点击一个按钮时,你不仅仅是点击了那个按钮。在浏览器看来,你同时还点击了按钮所在的容器、整个页面、甚至 window。
事件冒泡 指的是,当一个元素上的事件被触发时,该事件会从这个元素开始,逐级向上层父元素传播,直到 document 对象。
- 比喻: 就像往水里扔一块石头(触发事件的元素),涟漪(事件)会从中心点不断向外扩散(向父元素传播)。
2. 什么是事件委托?
基于事件冒泡的原理,我们不必为每个子元素都绑定事件监听器,而是只在它们的父元素上绑定一个监听器。这个父元素就像一个"受委托"的代表,统一处理所有子元素上冒泡过来的事件。
场景对比
假设我们有一个商品列表 <ul>,里面有很多 <li> 项,我们想在点击每个 <li> 时获取其内容。
常规做法 (不推荐):
javascriptconst items = document.querySelectorAll('ul li') items.forEach(item => { item.addEventListener('click', () => { console.log('你点击了:', item.textContent) }) })- 缺点:
- 性能开销大: 如果有 1000 个
<li>,就需要创建 1000 个事件监听器,占用大量内存。 - 维护困难: 如果通过 JS 动态添加了一个新的
<li>,你需要手动为这个新元素再次绑定事件。
- 性能开销大: 如果有 1000 个
- 缺点:
事件委托 (推荐):
javascriptconst list = document.querySelector('ul') list.addEventListener('click', event => { // 只有当被点击的确实是 li 元素时才响应 if (event.target.tagName === 'LI') { console.log('你点击了:', event.target.textContent) } })- 优点:
- 性能好: 无论有多少子元素,都只需要在父元素上绑定一个监听器。
- 维护方便: 动态添加的子元素也能被监听到,因为事件会自然冒泡到父元素,而父元素的监听器一直都在。
- 优点:
3. event.target vs event.currentTarget:关键区别
在处理委托事件时,正确区分 event.target 和 event.currentTarget至关重要。
| 属性 | 描述 | 在委托场景中 | 比喻 |
|---|---|---|---|
| event.target | 事件的真正来源。它是用户实际点击的那个最具体的元素。 | 可能是 <li>,也可能是 <li> 里的 <span> 或 <img>。 | 包裹的目标:快递员要去送一个包裹,target 就是包裹上写的具体门牌号,例如"302室"。 |
| event.currentTarget | 监听器所在的元素。也就是你调用 addEventListener 的那个元素。 | 永远是父元素 <ul>。 | 送达的大楼:快递员把车停在哪栋大楼下,这栋大楼就是 currentTarget,例如"幸福小区A栋"。 |
总结: 在事件委托的回调函数中,我们通常关心的是 event.target,因为它告诉我们是哪个子元素触发了事件。而 event.currentTarget 则始终是那个我们绑定事件的父元素。