一个点击事件
代码
<div class = 爷爷>
<div class = 爸爸>
<div class = 儿子>
文字
</div>
</div>
</div>
复制代码
即.爷爷>.爸爸>.儿子
,给三个div分别添加事件监听 fnYe / fnBa / fnEr
问题1:点击了谁
点击文字,算不算点击儿子?
点击文字,算不算点击爸爸?
点击文字,算不算点击爷爷?
答案:都算
问题2:调用顺序
点击文字,最先调用 fnYe / fnBa / fnEr
中的哪一个函数?
答案:都行
由来
IE5和网景
IE5认为先调fnEr
,网景认为先调fnYe
。
2002年,W3C发布标准,文档名为 DOM Level 2 Events Specification,规定浏览器应该同时支持两种调用顺序。
首先按爷爷=>爸爸=>儿子顺序看有没有函数监听
然后按儿子=>爸爸=>爷爷顺序看有没有函数监听
有函数监听就调用,并提供时间信息,没有就跳过
术语
从外向内找监听函数,叫事件捕获
从内向外找监听函数,叫时间冒泡
并不是说 fnYe / fnBa / fnEr
都要调用两次,开发者自行选择把f fnYe / fnBa / fnEr
放在捕获阶段或冒泡阶段
示意图
addEventListener
绑定事件API
IE5*: baba.attachEvent('onclick',fn) //冒泡
网景: baba.addEventListener('click',fn) //捕获
W3C: baba.addEventListener('click',fn,bool)
复制代码
如果bool不传或为falsy
就让fn走冒泡,即当浏览器在冒泡阶段发现baba有fn监听函数,就会调用fn,并提供事件信息
如果bool为true
就让fn走捕获,即当浏览器在捕获阶段发现baba有fn监听函数,就会调用fn,并提供时间信息
代码演示
冒泡演示
捕获演示
注意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先执行?
答案:f1先执行,如果两行调换位置,f2先执行。
取消冒泡
捕获不可取消,但是冒泡可以取消
div.stoppropatation()
复制代码
可中断冒泡,浏览器不再向上走,一般用于封装某些独立的组件。
不可阻止默认动作
有些事件不能阻止默认动作
MDN搜索scroll event,能看到Bubbles(该事件是否冒泡,所有冒泡都可取消)和 Cancelable(开发者是否可以阻止默认事件),Cancelable与冒泡无关。
最好是看英文版,中文版内容不全。
如何阻止滚动
scroll事件不可阻止默认动作
阻止scroll默认动作没用,因为先有滚动才有滚动事件
要阻止滚动,可以组织wheel和touchstart的默认动作
注意需要找准滚动条所在的元素,可用CSS让滚动条 width: 0
CSS也行
使用overflow:hidden
可直接取消滚动条
但此时JS依然可以修改scrollTop
自定义事件
浏览器自带事件
一共100多种事件,点击查看MDN
自定义事件
开发者可以在自带事件之外,自定义一个事件
事件委托
场景一
给100个按钮添加点击事件
监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个。
场景二
监听目前不存在的元素的点击事件
监听祖先,等点击的时候看看是不是想要监听的元素即可。
优点
省监听数(内存)
可以监听动态元素
封装事件委托
要求
写出这样一个函数on('click','#testDiv','li',fn)
,当用户点击#testDiv
里的li元素时,调用fn函数,要求用到事件委托。
代码
答案一:封装事件委托代码
答案二:递归判断 target / target的爸爸 / target的爷爷
整合进jQuery
可以尝试实现$('#xxx').on('click','li',fn)
JS支持事件吗
答
支持,也不支持。
本节课讲的DOM事件不属于JS的功能,术语浏览器提供的DOM功能(DOM和JS是平行关系)
JS只是调用了DOM提供的addEventListener
而已
问
如何让JS支持事件?请手写一个事件系统。