事件是用户或者浏览器自己执行的某种动作,是文档或者浏览器发生的一些交互瞬间,比如点击(click)按钮等,这里的click就是事件的名称。JS 与 HTML 之间的交互是通过事件实现的,DOM支持大量的事件。
事件分发和DOM事件流
众所周知,DOM 是个树形结构,我们在页面上点击一个元素,事件对象将通过 DOM 事件流确定的 DOM 树进行传播。
事件对象被调度到事件目标。但是在分发之前,必须首先确认事件对象的传播路径。
在事件传播过程,IE 认为应该先从最小的子元素开始查找事件对象,然后往上传给每一级的父元素,这种由内向外的查找事件对象方式,叫事件冒泡 。
而网景认为应该从最顶层的元素开始查找,逐层往下找,这种由外向内的查找事件对象方式,叫事件捕获。
最后,2002年,W3C 发布标准,规定浏览器应该同时支持两种调用顺序,于是有了如图的事件流。
事件流分为三个阶段:事件捕获阶段、目标阶段、事件冒泡阶段。
目标阶段,活动对象到达事件对象的事件目标。如果事件类型指示事件不会冒泡,则该事件对象将在此阶段完成后停止。
开发者可以自由选择将事件对象放在捕获阶段还是冒泡阶段。
事件绑定
- IE 5:element.attachEvent(‘onclick’, fn)// 冒泡
- 网景:element.addEventListener(‘onclick’, fn)// 捕获
- W3C:element.addEventListener(‘onclick’, fn, bool)
如果 bool 不传或为 falsy ,fn 就会走冒泡阶段。即当浏览器进入冒泡阶段发现 element 有 fn 监听函数,就会调用 fn 函数,并提供事件信息。
如果 bool 为 true ,fn 就会走捕获阶段。即当浏览器进入捕获阶段发现 element 有 fn 监听函数,就会调用 fn 函数,并提供事件信息。
注意:e 对象被传给所有监听函数。事件结束后,e 对象就不存在了。
target v.s currentTarget
区别
e.target是用户操作的元素e.currentTarget是程序员监听的元素
特例
当只有一个 div 被监听,fn 分别在捕获阶段和冒泡阶段监听 click 事件
div.addEventListener('click', f1)div.addEventListener('click', f2, true)
此时,谁先监听就会先执行。
取消冒泡和不可阻止默认动作
取消冒泡
捕获接断不可取消,但是冒泡阶段可以取消。我们通过 e.stopPropagation() 可以中断冒泡,浏览器不再向上走。一般用于封装某些独立的组件。
不可阻止默认动作
有些事件不能阻止默认动作。以 scroll event 为例,看到 Bubbles 和 Cancelable。
- Bubbles 为该事件是否冒泡,所有冒泡都可取消
- Cancelable 为开发者是否可以阻止默认事件
自定义事件
我们也可以自定义事件
element.addEventListener('click', () => {const event = new CustomEvent('custom', {"detail": {name: "custom", age: 18}})element.dispatchEvent(event)})element.addEventListener('custom', (e) => {console.log('custom')console.log(e)})
