Event 流 / 冒泡
DOM 事件传播的 3 个阶段:
- 捕获阶段(Capturing phase):event(从 Window)向下走近元素。
- 目标阶段(Target phase):event 到达目标元素。
- 冒泡阶段(Bubbling phase):event 从元素上开始冒泡。
capture
默认是在 3 阶段开始捕获处理事件。
但是也可以在 1 阶段 capture event,:
js
elem.addEventListener(..., {capture: true})
// 或
elem.addEventListener(..., true)event.stopPropagation() 是可以在 capture 阶段终止时间传递下去的。
冒泡
html
<form onclick="alert('form')">
FORM
<div onclick="alert('div')">
DIV
<p onclick="alert('p')">P</p>
</div>
</form>冒泡是自下而上的。
先 p,后 div,最后 form。
停止冒泡
event.stopPropagation() 停止冒泡。
警告
随意的阻止冒泡(event.stopPropagation) 会产生隐藏的陷阱,除非你真的深思熟虑。
e.stopPropagation() 不会阻滞同层级 event,比如多个 onclick。
e.stopImmediatePropagation() 会 阻止冒泡 并且阻止兄弟们的 event
target 与 currentTarget
target 是发起事件的元素(事发地)
currentTarget 是当前元素, 在 event 中等于 this 。
html
<div id="clickroot">
<div id="clickchild">click me</div>
</div>
<script>
clickroot.addEventListener("click", {
handleEvent(event) {
console.log("root", event.currentTarget, event.target, event);
},
});
clickchild.addEventListener("click", (e) => {
console.log("child", event.currentTarget, event.target, event);
});
</script>点击 clickchild,两个 click 都会触发。
child 中的 currentTarget 和 target 都是 child。
root 中的 currentTarget 是 root(clickroot) ,而 target 都是 child
事件委托
html
<div id="menu">
<button data-action="save">Save</button>
<button data-action="load">Load</button>
<button data-action="search">Search</button>
</div>
<script>
const handlers = {
save(){}
load(){}
search(){}
}
menu.onclick = (event)=> {
// action 是 data-action 的值
let action = event.target.dataset.action;
handlers[action]()
};
</script>