35. DOM事件与事件委托
DOM 事件与事件委托
JS 编程接口
点击事件
从这个东西开始研究
代码
即 .爷爷>.爸爸>.儿子
给三个div分别添加事件监听 fnYe / fnBa / fnEr
提问1:点击了谁
点击文字,算不算点击儿子?
点击文字,算不算点击爸爸?
点击文字,算不算点击爷爷?
答案:都算
提问2:调用顺序
点击文字,最先调用 fnYe / fnBa / fnEr 中的哪一个函数?
答案:都行。
IE 5 认为先调 fnEr,网景认为先调 fnYe,然后掐上了
最后闹到了 W3C
和事佬 W3C
2002 年,W3C 发布标准
文档名为 DOM Level 2 Events Specification
规定浏览器应该同时支持两种调用顺序
首先 按 爷爷 => 爸爸 => 儿子 顺序看有没有函数监听
然后 按 儿子 => 爸爸 => 爷爷 顺序看有没有函数监听
有监听函数就调用,并提供事件信息,没有就跳过
术语
从外向内 找监听函数,叫 事件捕获
从内向外 找监听函数,叫 事件冒泡
疑问:那岂不是 fnYe / fnBa / fnEr 都调用两次?非也!
开发者 自己选择 把 fnYe 放在 捕获阶段 还是放在冒泡阶段
示意图
addEventListener
事件绑定 API
IE 5*:baba.attachEvent('onclick', fn) // 冒泡
网景:baba.addEventListener('click',fn) // 捕获
W3C:baba.addEventListener('click', fn, bool)
就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听函数,就会调用 fn,并提供事件信息
如果 bool 为 true
就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息
*2020 之后, 永远 不要学习关于 IE 5、6、7、8、9、10、11 的知识,用到再搜
你可以选择把 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 先执行?
如果把两行调换位置后,请问哪个先执行?
错误答案:f2 先执行
正确答案:谁先监听谁先执行
总结:这是一个特例
取消冒泡
捕获不可取消,但冒泡可以
e.stopPropagation() 可中断冒泡,浏览器不再向上走
通俗来说:有人打我,我自己解决,别告诉我老子
一般用于封装某些独立的组件
不可阻止默认动作
有些事件不能阻止默认动作
MDN 搜索 scroll event,看到 Bubbles 和 Cancelable
Bubbles 的意思是该事件是否冒泡
Cancelable 的意思是开发者是否可以取消冒泡
Cancelable 与冒泡无关
推荐看 MDN 英文版,中文版内容不全
插曲:如何阻止滚动
scroll 事件 不可阻止默认动作
阻止 scroll 默认动作没用,因先有滚动才有滚动事件
要阻止滚动,可阻止
wheel
和touchstart
的默认动作但是滚动条还能用,可用 CSS 让滚动条 width: 0
CSS 也行
使用 overflow: hidden 可以直接取消滚动条
但此时 JS 依然可以修改 scrollTop
小结
target 和 currentTarget
一个是用户点击的,一个是开发者监听的
取消冒泡
e.stopPropagation()
事件的特性
Bubbles 表示是否冒泡
Cancelable 表示是否支持开发者取消冒泡
如 scroll 不支持取消冒泡
如何禁用滚动
取消特定元素的 wheel 和 touchstart 的默认动作
自定义事件
浏览器自带事件
提问
开发者能不能在自带事件之外,自定义一个事件
事件委托
场景一
你要给 100 个按钮添加点击事件,咋办?
答:监听这 100 个按钮的祖先,等冒泡的时候判断 target 是不是这 100 个按钮中的一个
代码示例:
场景二
你要监听目前不存在的元素的点击事件,咋办?
答:监听祖先,等点击的时候看看是不是我想要监听的元素即可
优点
省监听数(内存)(就是省内存)
可以监听动态元素(比如一开始元素不存在)
封装事件委托
要求
写出这样一个函数 on('click', '#testDiv', 'li', fn)
当用户点击 #testDiv 里的 li 元素时,调用 fn 函数
要求用到事件委托
答案一
判断 target 是否匹配 'li'
答案二
整合进 jQuery
有兴趣可以自己实现 $('#xxx').on('click', 'li', fn)
JS 支持事件吗
答
支持,也不支持。本节课讲的 DOM 事件不属于 JS 的功能,术语浏览器提供的 DOM 的功能
JS 只是调用了 DOM 提供的 addEventListener 而已
追问
如何当 JS 支持事件?请手写一个事件系统。
目前大家的水平还写不出来,可以先思考一段时间。
希望你对 DOM 事件,有一个完整的了解
最后更新于
这有帮助吗?