DOM事件与事件委托
点击事件
- W3C规定了浏览器应该同时支持两种调用顺序
- 首先按照爷爷=>爸爸=>儿子 顺序看看有没有函数监听
- 然后按照儿子=>爸爸=>爷爷 顺序看看有没有函数监听
- 有监听函数就调用,并提供事件信息,没有就跳过
术语
- 从外向内找监听函数,就事件捕获
- 从内向外找监听函数,叫事件冒泡
疑问:那岂不是都调用了两次?不是!
开发者自己选择把元素放在捕获阶段还是放在冒泡阶段
示意图
addEventListener
事件绑定API
- IE5*:bab.attachEvent(‘onclick’,fn) //冒泡
- 网景:bab.addEventListener(‘click’,fn) //捕获
- W3C:bab.addEventListener(‘click’,fn,bool)
如果bool不传或为falsy
- 就让fn冒泡,即当浏览器在冒泡阶段发现bab有fn监听函数,就会调用fn,并提供事件信息
如果bool为true
- 就让fn走捕获,即当浏览器在捕获阶段发现bab有fn监听函数,就会调用fn,并提供事件信息
可以选择把fn放在哪边
代码图解
两个疑问
- 子元素被点击了,算不算点击父元素?
- 那么先调用父元素的函数还是先调用子元素的函数?
捕获与冒泡
- 捕获说先调用父元素的监听函数
- 冒泡说先调用子元素的监听函数
W3C事件模型
- 先捕获(先父=>子) 在冒泡 (再子=>父)
- 注意e对象被传给所有监听函数
- 事件结束后,e对象就不存在了
target V.S. currentTarget
区别
- e.target-用户操作的元素
- e.currentTarget-程序员监听的元素
- this是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():取消冒泡
e.stopPropagation()可打断冒泡,浏览器不再向上走
- 一般用于封装某些独立组件
- 注意:捕获不可以取消但是冒泡可以(有些事件也不能够取消冒泡)
事件委托
我委托一个元素帮我监听我本该监听的东西,比如onclick
场景1:
- 要给100个按钮添加点击事件,咋办?
- 答:监听这个100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个
场景2:
- 你要监听目前不存在的元素的点击事件?
- 答:监听祖先,等点击的时候看看是不是监听的元素即可。
- 优点:省监听数(内存),可以动态监听元素
封装一个事件委托
只要实行一个函数就可以实现事件委托
要求:
- 写出这样一个函数on('click','#testDiv','li',fn)
- 当用户点击#testDiv里面的li元素时,调用fn函数
要求用到事件委托
- 答案1:判断target是否匹配'li'
- 答案2:target/target的爸爸/target的爷爷