DOM事件模型和事件委托(上)
TL;DR
事件监听
| addEventListener('click',fn,bool);
|
- 如果bool值不传或为falsy,fn走冒泡
- 如果bool值为true,fn走捕获
target和currentTarget
e.target 是用户操作的元素
e.currentTarget 是程序员监听的元素
举例:
| div>span{文字} 在div上绑定了事件监听函数 用户点击文字后,e.target 指span,e.currentTarget指div
|
捕获和冒泡都可以阻止:阻止捕获和冒泡阶段中当前事件的进一步传播(注意是都可以,MDN文档有解释,实践也证明如此)。
但是,它不能防止任何默认行为的发生; 例如,对链接的点击仍会被处理。
如果要停止这些行为,请参见 preventDefault 方法,它可以阻止事件触发后默认动作的发生。
| const event = new CustomEvent("eventName", customEventInit);
|
customEventInit包含detial、bubbles、cancelable三个key值。
| 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 事件模型/事件机制:对每个事件先捕获再冒泡。

举例
预览: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; };
level4.addEventListener('click',(e)=>{ e.stopPropagation(); });
$('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.dispatchEvent(event); });
div1.addEventListener("newEvent", (e) => { console.log("触发newEvent事件"); console.log(e.detail); }); </script> </body>
|
面试题:
请简述 DOM 事件模型或 DOM 事件机制。
答:
捕获:当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。
冒泡:浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。
W3C 事件模型/事件机制:对每个事件先捕获再冒泡。