# 事件三个阶段
- 捕获阶段:事件从顶部(window)向下走近元素
<div id="parent"> <div id="child"></div> </div> <script> const child = document.getElementById('child') const parent = document.getElementById('parent') child.addEventListener('click', function(event) { console.log('child true') }, true) parent.addEventListener('click', function(event) { console.log('parent true') }, true) window.addEventListener('click', function(event) { console.log('window true') }, true) // 点击child元素,依次打印window true-->parent true-->child true </script>
- 目标阶段:事件到达目标元素同一个元素事件的触发顺序,就是注册的顺序
<div id="parent"> <div id="child"></div> </div> <script> const child = document.getElementById('child') const parent = document.getElementById('parent') child.addEventListener('click', function(event) { console.log('child false') }, false) child.addEventListener('click', function(event) { console.log('child true') }, true) child.addEventListener('click', function(event) { console.log('child second false') }, false) // 点击child元素,依次打印child false-->child true-->child second false </script>
- 冒泡阶段:事件从元素上开始向顶层冒泡虽然形式上有 3 个阶段,但第 2 阶段(“目标阶段”:事件到达元素)没有被单独处理;
<div id="parent"> <div id="child"></div> </div> <script> const child = document.getElementById('child') const parent = document.getElementById('parent') child.addEventListener('click', function(event) { console.log('child false') }, false) parent.addEventListener('click', function(event) { console.log('parent false') }, false) window.addEventListener('click', function(event) { console.log('window false') }, false) // 点击child元素,依次打印child false-->parent false-->window false </script>
捕获阶段和冒泡阶段的处理程序都在该阶段被触发
# addEventListener
我们使用addEventListener
来进行事件的监听
element.addEventListener(event, handler, [options])
event
: 事件名,例如:"click"handler
: 处理程序options
: 可选对象,具有三个属性once
:如果为 true,那么会在被触发后自动删除监听器capture
: 事件处理的阶段,true为捕获,false为冒泡passive
: 如果为 true,那么处理程序将不会调用preventDefault()
- 简写形式
element.addEventListener(event, handler, false)
等同于element.addEventListener(event, handler, { capture: false})
# 事件对象
阻止冒泡
event.stopPropagation()
停止向上冒泡,但是当前元素上的其他处理程序都会继续运行event.stopImmediatePropagation()
用于停止冒泡,并阻止当前元素上的其他处理程序运行event.cancelBubble = true
停止冒泡,不标准的属性,已废弃,尽量不要使用该特性
阻止浏览器默认行为
event.preventDefault()
- 如果处理程序是使用
on<event>
分配的,那返回false
也同样有效 event.cancelable = true
常见的浏览器默认行为
- 在文本上按下鼠标按钮并移动选中文本。
- 点击一个链接,触发导航到该
url
- 鼠标右键,显示上下文菜单
target
与currentTarget
event.target
是引发事件的“目标”元素,它在冒泡过程中不会发生变化event.currentTarget
是“当前”元素,其中有一个当前正在运行的处理程序
# 事件委托
通常用于为许多相似的元素添加相同的处理,不必为每个元素分配一个处理程序,而是将单个处理程序放在它们的共同祖先上。
在处理程序中,我们获取 event.target
以查看事件实际发生的位置并进行处理。
- 一个小
demo
要求点击li
元素时,弹出li
元素的文本,点击其他元素无反应<ul id="ul"> <li>1</li> <li>2</li> <li>3</li> </ul> <script> const ul = document.getElementById('ul') ul.addEventListener('click', function(event) { const target = event.target if(target.tagName === 'LI') { alert(target.innerText) } }) </script>
# 自定义事件
- 一个小
demo
进入页面之后,会有<div id="test">test</div> <script> const testDom = document.getElementById("test") testDom.addEventListener('test', function(event) { alert('test') }) const testEvent = new Event('test') testDom.dispatchEvent(testEvent) </script>
alert
弹窗。使用Event
构造事件,使用dispatchEvent
触发事件 - 事件构造器
Event
let event = new Event(type, [options])
type
: 事件类型,可以是像这样 "click" 的字符串options
: 具有两个可选属性的对象bubbles
: 如果为 true,那么事件会冒泡cancelable
: 如果为 true,那么“默认行为”就会被阻止
CustomEvent
在第二个参数中,我们可以添加一个附加的属性detail
,剩下的和Event
一样
event.isTrusted
来自真实用户操作的事件,event.isTrusted
属性为true
; 对于脚本生成的事件,event.isTrusted
属性为false
# 参考文章
← 浏览器渲染原理 实现debounce →