点击事件
<
提问1:点击了谁
- 点击文字,算不算点击儿子?
- 点击文字,算不算点击爸爸?
- 点击文字,算不算点击爷爷?
- 答案:都算
提问2:调用顺序
- 点击文字,最先调用 fnYe / fnBa / fnEr 中的哪一个函数?
- 答案:都行
- IE5 认为先调 fnEr,网景认为先调 fnYe,然后掐上了
- 最后闹到了 W3C
2002年,W3C 发布标准
- 规定浏览器应该同时支持两种调用顺序
- 首先按 爷爷 => 爸爸 => 儿子 顺序看有没有函数监听
- 然后按 儿子 => 爸爸 => 爷爷 顺序看有没有函数监听
- 由监听函数就调用,并提供事件信息,没有就跳过
术语
- 从外向内找监听函数,叫事件捕获
- 从内向外找监听函数,叫事件冒泡
疑问:这样是不是把 fnYe / fnBa / fnEr 都调用两次呐?=> 开发者可以自己选择把 fnYe 放在捕获阶段还是放在冒泡阶段
示意图
![80eaefd864d998502fe69dd3210582f6.png](https://img-blog.csdnimg.cn/img_convert/80eaefd864d998502fe69dd3210582f6.png)
addEventListener
事件绑定API
baba
如果 bool 不传或为 falsy
就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息。
如果 bool 为 true
就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn,并提供事件信息。
一个特例
背景
- 只有一个 div 被监听(不考虑父子同时被监听)
- fn 分别在捕获阶段和冒泡阶段监听 click 事件
- 用户点击的元素就是开发者监听的
代码
- div.addEventLisenter('clicl', f1)
- div.addEventLisenter('clicl', f2, true)
- 请问 f1 先执行还是 f2 先执行?
- 如果把两行代码调换位置后,请问哪个先执行?
- 答案:谁先监听谁先执行。 => 这是一个特例
target V.S. currentTarget
区别
- e.target - 用户操作的元素
- e.currentTarget - 开发者监听的元素
- this 是 e.currentTarget,不推荐使用
举例
- div > span {文字},用户点击文字
- e.target 就是 span
- e.currentTarget 就是 div
取消冒泡
捕获不可取消,但冒泡可以
- e.stopPropagation() 可中断冒泡,浏览器不再向上走
- 一般用于封装某些独立的组件
不可取消冒泡
有些事件不可取消冒泡
- MDN 搜索 scroll event ,看到 Bubbles 和 Cancelable
- Bubbles 的意思是该事件是否冒泡
- Cancelable 的意思是开发者是否可以取消冒泡
上面提到 scroll ,那么如果阻止滚动
首先scroll 事件不可取消冒泡
- 阻止 scroll 默认动作没用,因先有滚动才有滚动事件
- 要阻止滚动,可阻止 wheel 和 touchstart 的默认动作
- 需要找准滚动条所在的元素
![3f7af68a233ca76e7ce7be77dc1990b8.png](https://img-blog.csdnimg.cn/img_convert/3f7af68a233ca76e7ce7be77dc1990b8.png)
- 但是滚动条还能用,可用 CSS 让滚动条 display: none
CSS 也可以
- 使用 overf: hidden 可以直接取消滚动条
- 但此时 JS 依然可以修改 scrollTop
事件委托(event.target 属性可以实现事件委托)
场景一
- 现在需要给100个按钮添加点击事件,怎么办?
- 答:监听这100个按钮的祖先,等冒泡的时候判断 target 是不是这100个按钮中的一个。
场景二
- 现在要监听目前不存在的元素的点击事件,怎么办
- 答:监听祖先,等点击的时候看看是不是我想要监听的元素即可
优点
- 省监听数(内存)
- 可以监听动态元素
封装事件委托
要求
- 函数 on('click', '#div1', 'button',fn)
- 当用户点击 #div1 里的 button 元素时,调用 fn 函数
- 需要用到事件委托
答案一
- 判断 target 是否匹配 'button'
const
首先通过这个 on 函数理解事件委托,给传入 element 参数的元素添加一个监听,然后判断当前的 target 是否满足 selector,如果满足就调用函数,如果不满足就放过。
但是这个方法是有误区的,如果 传入 selector 参数的元素还被 span 包围了,也就是说 button 元素中还含有一个 span ,然后 span 元素里有文字内容,这时我点击 button,委托事件是不会触发的,因为实际上我点击的是 span 元素,例子如下所示:
const
答案二
- 递归判断 target / target 的爸爸 / target的爷爷
function
JS 支持事件吗?
- 支持,也不支持。上面所说的 DOM 事件不属于 JS 的功能,属于浏览器提供的 DOM 的功能
- JS 只是调用了 DOM 提供的 addEventListener