冒泡捕获

冒泡捕获

冒泡

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

冒泡:点击 p 元素,首先 alert p,其次 alert div,最后 alert form。从最内层的元素冒泡到最外层的元素。

阻止冒泡 stopPropagation

阻止向父元素冒泡:

event.stopPropagation()

示例:

<body onclick="alert(`the bubbling doesn't reach here`)">
  <button onclick="event.stopPropagation()">Click me</button>
</body>

阻止冒泡 stopImmediatePropagation

阻止向父元素冒泡,并且当前元素绑定的其它事件也不会执行:

event.stopImmediatePropagation()

举例:

$('p').click(event => event.stopImmediatePropagation())
$('p').click(event => console.log('这个事件不会执行'))

但是如果你调整一下顺序,这个事件就会执行了:

$('p').click(event => console.log('这个事件会执行'))
$('p').click(event => event.stopImmediatePropagation())

捕获

事件传播的三个阶段

DOM Events 描述了事件传播的三个阶段:

  • 捕获阶段 (事件从 HTML 方向一层一层地向目标元素方向传递)
  • 目标阶段 (事件到达目标元素)
  • 冒泡阶段 (事件从目标元素向 HTML 方向冒泡)

addEventListener

elem 添加捕获事件监听

elem.addEventListener(..., {capture: true})
// or, just "true" is an alias to {capture: true}
elem.addEventListener(..., true)

如果 capture 值是 false,那么会作为冒泡事件监听。

移除事件监听器,同样需要对应的参数。如果你是 addEventListener(..., true) 这样添加的事件,那么 removeEventListener(..., true) 需要这样移除。

示例

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form>FORM
  <div>DIV
    <p>P</p>
  </div>
</form>

<script>
  for(let elem of document.querySelectorAll('*')) {
    elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
    elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
  }
</script>

点击 p 元素,网页依次 alert 的是:

  • Capturing: HTML -> Capturing: BODY -> Capturing: FORM -> Capturing: DIV -> Capturing: P
  • Bubbling: P -> Bubbling: DIV -> Bubbling: FORM -> Bubbling: BODY -> Bubbling: HTML

参考