带你彻底搞懂JavaScript的事件流
目录
- DOM事件流
- 事件冒泡
- 事件捕获
- 情景一:直接在HTML中绑定事件
- 情景二:[domNode].onclick()方式——DOM0级
- 情景三:[domNode].addEventListener()方式——DOM2级
- 总结
DOM事件流 要明白事件流,首先我们要明白三点:
- 元素不是独立的,是串联在一起的
- 单个元素触发事件以后还会影响其他元素
- 事件流的方式:事件捕获(网景提出)、事件冒泡(IE提出)
文章图片
我们就以上图为例,假设你给div绑定了点击事件,当你点击了div后,其他元素也会受之牵连,会引起牵一发而动全身的效果。
事件流的方式有两种:
事件冒泡
、事件捕获
事件冒泡
文章图片
事件冒泡阶段:在点击完div后立即触发目标事件,然后再一层一层向上冒泡
事件捕获
文章图片
事件捕获阶段:在点击完div后不会立即触发div的事件,而是一层一层向下捕获,最终到达div才触发事件。
其实,这两种阶段,在日后的项目开发中都有可能遇见,因为不同的绑定事件方法,造就了不同的事件阶段(冒泡/捕获)
情景一:直接在HTML中绑定事件
【带你彻底搞懂JavaScript的事件流】效果:
文章图片
从上图可看出,当我们点击span标签以后,上层button身上的事件以及body身上的事件都会按冒泡顺序执行
情景二:[domNode].onclick()方式 —— DOM0级
html:
javascript:
var body = document.getElementsByTagName('body')[0]; var button = document.getElementsByTagName('button')[0]; var span = document.getElementsByTagName('span')[0]; body.onclick = function() {console.log('我是body')}; button.onclick = function() {console.log('我是button')}; span.onclick = function() {console.log('我是span')};
效果:
文章图片
我们发现,DOM0级绑定事件的方式依然是冒泡的形式
情景三:[domNode].addEventListener()方式 —— DOM2级
addEvenListener(事件名,事件触发后的回调,布尔值)
false(默认):表示在冒泡阶段调用事件处理程序true:表示在捕获阶段调用事件处理程序html:
javascript:
var body = document.getElementsByTagName('body')[0]; var button = document.getElementsByTagName('button')[0]; var span = document.getElementsByTagName('span')[0]; function theName() {console.log('我是' + this.nodeName)}; body.addEventListener('click',theName,false); button.addEventListener('click',theName,false); span.addEventListener('click',theName,false);
效果:
文章图片
我们可以看到当addEventListener的第三个参数为false(不写默认也是false)的时候,事件流为冒泡。
当我们把第三个参数改为true时:
......body.addEventListener('click',theName,true); button.addEventListener('click',theName,true); span.addEventListener('click',theName,true);
文章图片
我们发现,执行顺序为body ——> button ——> span,为事件捕获阶段。
DOM2级规定:
- 事件流包括三个阶段(1.捕获阶段 2.目标阶段 3.冒泡阶段)
执行循序
应遵循:捕获阶段 ——> 目标阶段 ——> 冒泡阶段
我们来看一道经典面试题:当我们点击baby婴儿时的输出顺序?
文章图片
html:
grandma奶奶mother妈妈daughterbaby婴儿
javascript:
var grandma = document.getElementsByClassName('grandma')[0]var mother = document.getElementsByClassName('mother')[0]var daughter = document.getElementsByClassName('daughter')[0]var baby = document.getElementsByClassName('baby')[0]function theName() {console.log('我是' + this.className); }baby.addEventListener('click', theName, false)//冒泡daughter.addEventListener('click', theName, true)//捕获mother.addEventListener('click', theName, true)//捕获grandma.onclick = theName//冒泡
结果:
文章图片
做题思路:
- 先给绑定好事件的元素划分是 捕获?冒泡?我们可以看到
daughter
和mother
为捕获
;baby
和grandma
为冒泡
- 因为DOM2规定先捕获后冒泡,因此会先打印daughter和mother其中之一
- 因为捕获是从上至下(dom根——>div),因此先打印mother后daughter
- 因为冒泡是从下至上(div——>dom根),因此打印baby后再打印grandma
总结 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- Framework没掌握好?字节技术大牛精编解析笔记带你系统学习...
- 这篇文章,带你全面了解外包公司
- 搞懂MySQL(各种)索引类型及其区别
- 技能分享|iPhone彻底删除的照片能恢复吗,2个找回永久删除照片的方法
- 路由|一图搞懂网络NAT映射
- 3·8节,一个小视频带你认识下这群才华与美貌兼具的宝藏女孩!
- kafka|2万字|30张图带你领略glibc内存管理精髓(因为OOM导致了上千万损失)
- 学习笔记(带你十天轻松搞定|学习笔记:带你十天轻松搞定 Go 微服务系列(四)- 产品服务)
- 最后一次,搞懂CSRF攻击!
- 学习笔记(带你十天轻松搞定|学习笔记:带你十天轻松搞定 Go 微服务系列(三)- 用户服务)