捕获与冒泡
从外向内找监听函数,叫事件捕获
从内向外找监听函数,叫事件冒泡
W3C事件模型
事件绑定API:addEventListener
IE:x.attachEvent(‘onclick’,fn) //冒泡
网景:x.addEventListener(‘click’,fn) //捕获
W3C:x.addEventListener(‘click’,fn,bool)
如果bool不传或为falsy
就让fn走冒泡,即当浏览器在冒泡阶段发现x有fn监听函数,就会调用fn,并提供事件信息如果bool为true
就让fn走捕获,即当浏览器在捕获阶段发现x有fn监听函数,就会调用fn,并提供事件信息
总结:
- 先捕获,再冒泡(正常情况下)
- 如果不存在父级元素或者只有一个节点元素,那么捕获和冒泡的先后顺序就是谁在前先走谁
- 注意e对象被传给所有监听函数
事件结束后,e对象就不存在了 - 捕获不可以取消,但所有冒泡皆可取消,默认动作有的可以取消有的不能取消
- e.stopPropagation()可中断冒泡,浏览器不再向上走
target vs currentTarget
两者的区别
e.target——用户操作的元素
e.currentTarget——程序员监听的元素
this是e.currentTarget,不推荐使用
举例
div>span{文字} ,当用户点击文字时
e.target 是 span
e.currentTarget 是 div
一个特例
只有一个div被监听(不考虑父子同时被监听)
fn分别在捕获阶段和冒泡阶段监听click事件
用户点击的元素就是开发者监听的
div.addEventListener(‘click’,f1)
div.addEventListener(‘click’,f2,true)
请问f1和f2谁先执行?
f1,因为谁先监听谁先执行!
自定义事件
浏览器自带事件,有100多种
开发者可以在自带事件之外,自定义一个事件
事件委托
每个函数都是对象,都会占用内存,所以当我们的页面中所包含的事件数量较多时,如果给每个节点绑定一个事件,加上事件处理程序,就会造成性能很差。还有一个问题是,某个元素节点是后来通过JavaScript动态添加进页面中的,这时候我们如果提前对它进行绑定,但此时该元素并不存在,所以会绑定事件会失败。解决上述两个问题的一个常用方案,就是使用事件委托。
场景一
- 要给100个按钮添加点击事件,咋办?
- 监听100个按钮的祖先id,等冒泡的时候判断target是不是这100个按钮中的一个代码示例
场景二
你要监听目前不存在的元素的点击事件,咋办?
监听祖先,等点击的时候看看是不是我想要监听的元素即可代码示例
总结事件委托的有点:
- 省监听数(内存)
- 可以监听动态元素
封装事件委托
要求:写出这样一个函数on(‘click’, ‘#testDiv’, ‘li’, fn)
注意:先搞清楚输入(封装的四个参数,事件绑定、元素选择器 Element.matches 、事件 event 对象,某些函数)在搞清楚输出
当用户点击#testDiv里的li元素时,调用fn函数
要求用到事件委托
答案一
判断target是否匹配’li’等选择器,代码示例
答案二
递归判断target / target的爸爸/target的爷爷。(当前元素不匹配button就看他的爸爸匹配不,只要我的祖先中某一项是button,说明点击的就是button),代码示例
整合进自己的jQuery
有兴趣可以自己实现$(’#xxx’).on(‘click’, ‘li’, fn)试试看~
JS支持事件吗
答
不支持。本次讲的DOM事件不属于JS的功能,是浏览器提供的 DOM的功能
JS只是调用了DOM提供的addEventListener而已