点击事件
关于点击事件,可以通过一下代码来进行解答。
<
再给三个div添加事件监听“fnNo1、fnNo2、fnNo3”,就是谁被点击了就执行谁。
问题一:点击了谁
- 点击文字,算不算点击“no1”?
答案:算!
- 点击文字,算不算点击“no2”?
答案:算!
- 点击文字,算不算点击“no3”?
答案:算!
通过以上代码可以得出,当我们点击子元素(no3)的时候,会将父元素和根元素同时点击一遍。
问题二:调用顺序
- 点击文字,最先调用fnNo1、fnNo2、fnNo3中的哪一个函数?
答案:都可以,主要看浏览器是这么实现的。
解析:在之前IE5认为应该先调用子元素,因为子元素最近所以先调用子元素。但是跟它同一时期的网景浏览器跟IE唱反调,网景说应该先调用跟元素,因为跟元素最大,所以应该通知跟元素。
W3C标准
后来W3C在2002年,发布了关于事件调用顺序的标准,文档名为“DOM Level2 Events Specification”,规定浏览器应该同时支持两种调用顺序。
- 首先按照根元素=>父元素=>子元素的顺序看看有没有函数监听。
- 然后按照子元素=>父元素=>根元素的顺序看看有没有函数监听。
有函数监听就调用,并提供事件信息,没有就直接跳过。
术语
- 从外向内找监听函数,叫事件捕获。
- 从内向外找监听函数,叫事件冒泡。
DOM冒泡阶段和捕获阶段示意图:
事件绑定API
addEventListener //绑定事件
IE5
- 如果bool不传或者不传为falsy
就让fn走冒泡,即当浏览器在冒泡阶段发现no2有fn监听函数,就会调用fn,并提供事件信息。
- 如果boll为true
就让fn走捕获,即当浏览器在捕获阶段发现no2有fn监听函数,就会调用fn,并提供事件信息。
小结!
两个疑问
- 子元素被点击,算不算点击根元函数?
算!因为这部分其中任意一个div被点击了,全都被点击了。
- 先调用根函数还是先调用子函数?
不确定!如果是在IE的浏览器就是先调用子函数,如果是在Firefox浏览器就是先调用父元函数。
捕获与冒泡
捕获:先调用父的监听函数 冒泡:先调用子的监听函数
W3C事件模型
先捕获(先父元素=>子元素)再冒泡(再子元素=>父元素)
注意!x对象被传给所有的监听函数,事件结束后,x对象就不存在了。
取消冒泡&不可取消冒泡
取消冒泡
- 捕获不可以取消,但是冒泡可以取消
x.stoPropagation() //取消冒泡
终端冒泡浏览器不是再往上走,一般用于封装某些独立的组件。
不可取消冒泡
- 有一些特殊事件不可取消冒泡
在MDN上面可以搜索scroll event,可以看到bubbles和Cancelable。
Bubbles 的意思是该事件是否支持冒泡。
Cancelable 的意思是开发者是否可以取消冒泡。
!来给代码加点料
如何阻止滚动
scroll事件不可以取消冒泡
阻止scroll默认动作没用,因为先有滚动才有滚动事件。想要阻止滚动,可以阻止wheel和touchstart的默认动作。注意!你需要找准滚动条所在的元素,但是滚动条还能用,可一用CSS让滚动条width:0
CSS也可以
使用overflow:hidden 可以直接取消滚动条,但是此时js依然可以修改scrollTop。
小结!
- target和currentTarget
前者属于用户点击的,后者属于是开发者监听的
- 取消冒泡
e.stopPropagation()
- 事件的特性
Bubbles 表示是否支持开发者取消冒泡
Cancelable 表示是否支持开发者取消冒泡
比如:scroll 就不支持取消冒泡
- 如何禁用滚动
取消特定的元素wheel和touchstart的默认动作
事件委托
事件委托可以大量节省内存占用,减少事件注册。
同时给多个事件添加点击事件
需要同时给多个事件添加监听,我们只需要对他的父元素进行监听,等到冒泡的时候判断target是不是这里面的其中一个。
给当前不存在的元素的元素添加点击事件
同样先要监听父级元素,等点击的时候看看是不是我想要监听的元素即可。