DOM事件模型和事件委托(上)

DOM事件模型和事件委托(上)

TL;DR

事件监听

1
addEventListener('click',fn,bool);
  • 如果bool值不传或为falsy,fn走冒泡
  • 如果bool值为true,fn走捕获

target和currentTarget

  • e.target 是用户操作的元素
  • e.currentTarget 是程序员监听的元素

举例:

1
2
3
div>span{文字}
在div上绑定了事件监听函数
用户点击文字后,e.target 指span,e.currentTarget指div

[event.stopPropagation](event.stopPropagation - Web API 接口参考 | MDN (mozilla.org))

捕获和冒泡都可以阻止:阻止捕获冒泡阶段中当前事件的进一步传播(注意是都可以,MDN文档有解释,实践也证明如此)。

但是,它不能防止任何默认行为的发生; 例如,对链接的点击仍会被处理。

如果要停止这些行为,请参见 preventDefault 方法,它可以阻止事件触发后默认动作的发生。

自定义事件

1
const event = new CustomEvent("eventName", customEventInit);

customEventInit包含detial、bubbles、cancelable三个key值。

发派事件

1
target.dispatchEvent(event);
  • event 是要被派发的事件对象。
  • target被用来初始化 事件 和 决定将会触发 目标。

1. DOM事件模型

1.1 DOM事件(流)

根据[维基百科](事件驱动程序设计 - 维基百科,自由的百科全书 (wikipedia.org))的定义:事件或者事件驱动程序设计Event-driven programming)是一种程序设计模型。这种程序运行流程是由用户的动作(如鼠标点击,键盘的按键动作)或者是由其他程序的指令性事件来决定的。

当事件发生在某个DOM节点上时,事件会在DOM结构中进行逐级的传播(propagation)。这个传播过程称为事件流

我们可以利用**事件监听 - Web API 接口参考 | MDN (mozilla.org)](https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener))**来控制页面对所触发事件发出响应:当事件触发时执行相应的程序,进而实现用户和网页的交互。

1.2 DOM事件模型——捕获和冒泡

根据W3C的[**DOM3级事件草案**](UI Events (w3.org)),浏览器应同时支持两种调用顺序,共三个事件阶段:

  • 捕获阶段(capture phase):事件对象从window开始,由目标元素的祖先传播到目标元素的的父母,自上而下传播。此阶段也称为捕获阶段
  • 目标阶段(target phase):事件对象到达它的的event target。此阶段也称为目标阶段
    • 如果事件类型指定了事件对象默认不冒泡(bubbles: false),则事件对象将在完成此阶段后停止。
  • 冒泡阶段(bubbling phase):事件对象以相反顺序自下向上,由目标元素开始,经过目标的父母向祖先元素传播,直到到window结束。此阶段也称为冒泡阶段

W3C 事件模型/事件机制:对每个事件先捕获再冒泡

Graphical representation of an event dispatched in a DOM tree using the DOM event flow

举例

预览:https://yichang8421.github.io/DOMEvent/dist/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<div class="level1 x">
<div class="level2 x">
<div class="level3 x">
<div class="level4 x">
<div class="level5 x">
<div class="level6 x">
<div class="level7 x"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="main.js"></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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const level1 = document.querySelector('.level1');
const level2 = document.querySelector('.level2');
const level3 = document.querySelector('.level3');
const level4 = document.querySelector('.level4');
const level5 = document.querySelector('.level5');
const level6 = document.querySelector('.level6');
const level7 = document.querySelector('.level7');

let n = 1;
const removeX = (e)=>{
const t = e.currentTarget;
setTimeout(()=>{
t.classList.remove('x');
},n*500);
n+=1;
};
const addX =(e)=>{
const t = e.currentTarget;
setTimeout(()=>{
t.classList.add('x');
},n*500);
n+=1;
};

// 在第四个div阻止冒泡
level4.addEventListener('click',(e)=>{
e.stopPropagation();
});

// 在第四个div阻止捕获
// level4.addEventListener('click',(e)=>{
// e.stopPropagation();
// },true);

$('div').each((i, e) => {
e.addEventListener('click', addX,);
});

$('div').each((i,e)=>{
e.addEventListener('click',removeX,true);
});

2. 自定义事件

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
<body>
<div id="div1">
<button id="button1">点击触发 自定义 事件</button>
</div>

<script>
button1.addEventListener("click", () => {
// 自定义事件
const event = new CustomEvent("newEvent", {
detail: {
name: "andy8421",
age: 18,
},
// 设置可以冒泡
bubbles: true,
// 不允许阻止冒泡
cancelable: false,
});

// 将自定义的事件发派给button1
button1.dispatchEvent(event);
});

div1.addEventListener("newEvent", (e) => {
console.log("触发newEvent事件");
console.log(e.detail);
});
</script>
</body>

面试题:

请简述 DOM 事件模型或 DOM 事件机制。

答:

捕获:当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。
冒泡:浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。
W3C 事件模型/事件机制:对每个事件先捕获再冒泡。


版权声明:本文作者为「Andy8421」.本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!