事件是在编程时系统内发生的动作或发生的事情(单击、鼠标移动、滚动页面等)。HTML DOM 使 JavaScript 有能力对 HTML 事件做出反应。JS与HTML之间的交互是通过事件实现的,DOM支持大量的事件。事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。
DOM事件模型分三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
代码举例:
<div class= “爷爷”><div class= “爸爸”><div class= “儿子”></div></div>
</div>
即 .爷爷>.爸爸>.儿子,分别添加事件监听 fnYe / fnBa / fnEr
提问1: 点击了谁?
点击文字, 算不算点击儿子;点击文字, 算不算点击爸爸;点击文字, 算不算点击爷爷
答: 都算
提问2: 调用顺序? 点击文字最先调用fnYe/fnBa/fnEr中的哪一个函数?
IE5调用顺序为fnEr->fnBa->fnYe, 网景调用顺序为fnYe->fnBa->fnEr
最后W3C制定标准
- 文件名为DOM Level 2 Events Specification
- 规定浏览器同时支持两种调用顺序
- 首先按爷爷=>爸爸=>儿子顺序看有没有函数监听
- 然后按儿子=>爸爸=>爷爷顺序看有没有函数监听
因此:从外向内找监听函数,叫事件捕获
从内向外找监听函数,叫事件冒泡
DOM事件模型示意图
addEventListener
事件绑定API
- IE5: baba.attachEvent('onclick', fn)//事件冒泡
- 网景: baba.addEventListener('click', fn)//事件捕获
- W3C: baba.addEventListener('click', fn, bool),
如果bool不传或为falsy, 则fn使用事件冒泡, 即当浏览器在冒泡阶段发现baba有监听函数,就会调用fn并提供事件信息;反之如果bool为true就让fn走捕获,即当浏览器在捕获阶段发现baba有fn监听函数,就会调用fn,并提供事件信息。
JS Binjs.jirengu.comtarget和currentTarget
e.target 是用户操作的元素
e.currentTarget是程序员监听的元素
例如:div>span{文字},用户点击文字,e.target就是span,e.currentTarget是div
特例:如果监听的元素就是用户点击的元素,那么谁先监听就谁先执行
只有一个div被监听(不考 虑父子同时被监听),fn分别在捕获阶段和冒泡阶段监听click事件
用户点击的元素就是开发者监听的
div.addEventLisenter('click', f1)
div.addEventLisenter('click', f2, true)
请问,f1 先执行还是f2先执行?如果把两行调换位置后,请问哪个先执行?
正确答案:谁先监听谁先执行
取消冒泡
捕获不可取消,但冒泡可以
e.stopPropagation()可中断冒泡,浏览器不再向上走,一般用于封装独立组件
不可取消冒泡:有些事件不可取消冒泡
例如:MDN搜索scroll event,看到Bubbles和Cancelable,Bubbles的意思是该事件是否冒泡
Cancelable的意思是开发者是否可以取消冒泡
如何阻止滚动?
滚动条是出现在document上面的
- 阻止scroll默认动作没用,因为先有滚动才有滚动事件
- 要阻止滚动,可阻止wheel和touchstart的默认动作
- 注意你需要找准滚动条所在的元素
- 但是滚动条还能用,可用CSS让滚动条width: 0
CSS也行
- 使用overflow: hidden可以直接取消滚动条
- 但此时JS依然可以修改scrollTop
自定义事件
浏览器自带事件有100多种
事件参考developer.mozilla.org如何自定义一个事件
事件委托
就是委托一个元素帮助监听本该监听的元素
场景一:
你要给100个按钮添加点击事件,咋办?
答:监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个
JS Binjs.jirengu.com场景二
你要监听目前不存在的元素的点击事件,咋办?
答:监听祖先,等点击的时候看看是不是我想要监听的元素即可
优点
- 省监听数(内存)
- 可以监听动态元素
封装事件委托
JS支持事件吗
答:支持,也不支持。DOM事件不属于JS的功能,术语浏览器提供的DOM的功能
JS只是调用了DOM提供的addEventListener而已