Skip to content

Event 流 / 冒泡

DOM 事件传播的 3 个阶段:

  1. 捕获阶段(Capturing phase):event(从 Window)向下走近元素。
  2. 目标阶段(Target phase):event 到达目标元素。
  3. 冒泡阶段(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>