JS-API-3-事件委托

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>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer');
const inner = document.querySelector('.inner');
const child = document.querySelector('.child');

// html 元素添加事件
document.documentElement.addEventListener('click', function () {
console.log('html...')
})

// body 元素添加事件
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>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer')
const inner = document.querySelector('.inner')

// 外层的盒子
outer.addEventListener('click', function () {
console.log('outer...')
}, true) // true 表示在捕获阶段执行事件

// 中间的盒子
outer.addEventListener('click', function () {
console.log('inner...')
}, true)
</script>
</body>

  1. addEventListener 第3个参数决定了事件是在捕获阶段触发还是在冒泡阶段触发
  2. addEventListener 第3个参数为 true 表示捕获阶段触发,false 表示冒泡阶段触发,默认值为 false
  3. 事件流只会在父子元素具有相同事件类型时才会产生影响
  4. 绝大部分场景都采用默认的冒泡模式(其中一个原因是早期 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) {
// alert(11)
// this.style.color = 'red'
// console.dir(e.target) // 就是我们点击的那个对象
// e.target.style.color = 'red'
// 我的需求,我们只要点击li才会有效果
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() {
// xxxxx
})

两个属性

// scrollTop 被卷去的头部

//scrollLeft 被卷去的左部

这两个值是可读写的(数字型)

注意:

获取HTML元素的写法

document.documentElement

document.documentElement.scrollTop

页面尺寸事件

  • 会在窗口改尺寸的时候触发
  • resize
  • 获取元素可见宽高(包含padding ,不包含border)
    • clientwidth
    • clientheight

元素尺寸和位置

  • 获取宽高
    • 获取元素自身宽高,包含border
    • offsetWidth,offsetHeight
    • 取出来的是数值,方便计算
  • 获取位置
    • 获取元素距离自己定位父级元素(带有定位的)的左,上距离
    • ==offsetLeft==和==offsetTop==注意是只读属性

​ element.getBoundingClientRect()

​ 方法返回元素的大小及其相对于视口的位置


JS-API-3-事件委托
https://wjcbolg.cn/2023/04/29/JS学习笔记8/
作者
JasonWang
发布于
2023年4月29日
许可协议
BY-JW