JS学习笔记8
事件流
事件流是对事件执行过程的描述,了解事件的执行过程有助于加深对事件的理解,提升开发实践中对事件运用的灵活度。
如上图所示,任意事件被触发时总会经历两个阶段:【捕获阶段】和【冒泡阶段】。
简言之,捕获阶段是【从父到子】的传导过程,冒泡阶段是【从子向父】的传导过程。
捕获和冒泡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <body> <h3>事件流</h3> <p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p> <div class="outer"> <div class="inner"> <div class="child"></div> </div> </div> <script> const outer = document.querySelector('.outer'); const inner = document.querySelector('.inner'); const child = document.querySelector('.child'); document.documentElement.addEventListener('click', function () { console.log('html...') }) document.body.addEventListener('click', function () { console.log('body...') })
outer.addEventListener('click', function () { console.log('outer...') }) outer.addEventListener('click', function () { console.log('inner...') }) outer.addEventListener('click', function () { console.log('child...') }) </script> </body>
|
执行上述代码后发现,当单击事件触发时,其祖先元素的单击事件也【相继触发】,这是为什么呢?
结合事件流的特征,我们知道当某个元素的事件被触发时,事件总是会先经过其祖先才能到达当前元素,然后再由当前元素向祖先传递,事件在流动的过程中遇到相同的事件便会被触发。
再来关注一个细节就是事件相继触发的【执行顺序】,事件的执行顺序是可控制的,即可以在捕获阶段被执行,也可以在冒泡阶段被执行。
如果事件是在冒泡阶段执行的,我们称为冒泡模式,它会先执行子盒子事件再去执行父盒子事件,默认是冒泡模式。
如果事件是在捕获阶段执行的,我们称为捕获模式,它会先执行父盒子事件再去执行子盒子事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <body> <h3>事件流</h3> <p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p> <div class="outer"> <div class="inner"></div> </div> <script> const outer = document.querySelector('.outer') const inner = document.querySelector('.inner')
outer.addEventListener('click', function () { console.log('outer...') }, true) outer.addEventListener('click', function () { console.log('inner...') }, true) </script> </body>
|
addEventListener
第3个参数决定了事件是在捕获阶段触发还是在冒泡阶段触发
addEventListener
第3个参数为 true
表示捕获阶段触发,false
表示冒泡阶段触发,默认值为 false
- 事件流只会在父子元素具有相同事件类型时才会产生影响
- 绝大部分场景都采用默认的冒泡模式(其中一个原因是早期 IE 不支持捕获)
阻止冒泡
默认有冒泡模式,所以容易导致事件影响到父级元素
借助于事件对象
1 2 3 4 5 6
| child.addEventListener('click', function (e) { console.log('child...')
e.stopPropagation() })
|
阻止默认行为
某些情况下需要阻止默认行为的发生,如阻止链接的跳转,表单域跳转
preventDefault()
事件解绑
L0 btn.onclick=null
L2
1 2 3 4 5 6 7 8 9
| funcition fn(){ } btn.addEventListener('click',fn) btn.removeEventListener('click',fn)
匿名函数无法解绑
|
鼠标经过事件的区别
- mouseover和mouseout有冒泡
- mouseover和mouseleave没有冒泡事件
事件委托
利用事件冒泡的特点,减少注册次数,提高程序性能
- 给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
1 2 3 4 5 6 7 8 9 10 11 12 13
| 应用中需要找到真正触发的元素,e.target const ul = document.querySelector('ul') ul.addEventListener('click', function (e) { if (e.target.tagName === 'LI') {(大写) e.target.style.color = 'red' } }) ul是父元素
|
可以用自定义属性来做相同元素的索引号。data-xx=’0’;
对象.dataset.xx
其他事件
页面加载事件
事件名:load (等页面所有资源加载完毕)
1 2 3
| window.addEventListener('load',function(){ })
|
给window添加load事件
事件名:DOMContentLoaded
(初始HTML文档加载完成后即可执行)
元素滚动事件
- 滚动条在滚动时持续触发的事件
- 事件名:scroll
- 监听整个页面滚动(也可以监听有滚动条的DIV)
1 2 3
| window.addEventListener('scroll', function() { })
|
两个属性
// scrollTop 被卷去的头部
//scrollLeft 被卷去的左部
这两个值是可读写的(数字型)
注意:
获取HTML元素的写法
document.documentElement
document.documentElement.scrollTop
页面尺寸事件
- 会在窗口改尺寸的时候触发
- resize
- 获取元素可见宽高(包含padding ,不包含border)
元素尺寸和位置
- 获取宽高
- 获取元素自身宽高,包含border
- offsetWidth,offsetHeight
- 取出来的是数值,方便计算
- 获取位置
- 获取元素距离自己定位父级元素(带有定位的)的左,上距离
- ==offsetLeft==和==offsetTop==注意是只读属性
element.getBoundingClientRect()
方法返回元素的大小及其相对于视口的位置