1. DOM 事件模型
DOM 事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播。
捕获阶段:事件从 window 对象自上而下向目标节点传播的阶段;
冒泡阶段:事件从目标节点自下而上的向 window 对象传播的阶段。
开发者可以自己选择将函数放在捕获阶段或者冒泡阶段。
如果 bool 的值为 flase 或者不填,则默认浏览器在冒泡阶段调用 fn,如果是 ture 则在捕获阶段调用 fn
el.addEventListener(event-name.fn,bool)
2. target,currentTaget 和 取消冒泡
2.1 e.target 和 e.currentTarget
e.target 是被用户操作的元素,而 e.currentTarget 是开发者监听的元素。
举例:
<div>
<span> 文字 </span>
</div>
如果用户点击了文字,那么 e.target 就是 span,e.currentTatget 就是 div
2.2 取消冒泡
捕获不可取消,但是冒泡可以。
e.stopPropagation() // 用于中断冒泡
3. 事件委托
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的委托。委托其他元素监听需要监听的元素。
事件委托的有点是:省监听数(内存),可以监听动态元素
举例1(给多个按钮添加点击事件):
<div id='div1'>
<button> 1 </button>
<button> 2 </button>
<button> 3 </button>
<button> 4 </button>
<button> 5 </button>
</div>
div1.addEventListener('click',(e)=>{ // 给 div1 添加点击事件
const t = e.target // 被操作的元素(button)赋值为 变量t
if(t.tagName.toLowerCase()==='button'){ // 如果 t 的标签名 的小写 全等于 button,那么执行函数
console.log('button 被点击了')
}
})
上述的例子,如果直接给 button 添加点击事件需要 5 个监听器,而如果给 div 添加点击事件,只需要 1 个监听器,节约了内存。
举例2(监听目前不存在的元素):
setTimeout(()=>{
const button = document.createElement('button')
button.textContent = 'click 1'
div1.appendChild(button)
},1000)
div1.addEventListener('click',(e)=>{ // 给 div1 添加点击事件
const t = e.target // 将被操作的元素(button,目前不存在)赋值给 变量t
if(t.tagName.toLowerCase()==='button'){ // 如果 t 的标签名 的小写 全等于 button,那么执行函数
console.log('button 被点击了')
}
})
上述的例子中,'click 1' 这个 button 是在一秒后生成的,但是使用事件委托,将事件挂在 div1 上,仍然可以获取到这个 button,因此事件委托可以用来监听目前不存在的元素。
4. 封装事件委托
(以后补充...)