js event flow (capture phase, target phase, bubbling phase) cancels the browser's default bubbling behavior

I have been typing code for too long. I can’t remember all the knowledge I remembered very clearly when I was studying. The more I learn, the more I can’t.

I don't know how long it will last...

insert image description here

what is event flow

了解什么是事件流,主要的是了解 ·事件·的概念:
 - 前端页面的交互主要就是由事件驱动来实现的;
 - 而类似于 dom的 click、change,浏览器的 onload, 键盘的 keypress都可以称之为事件。
 - 想要具体了解的话,可以去看《JavaScript权威指南》的第17章。

js的事件流指的是: 
	- 事件的流向: 浏览器响应一个 `事件` 的执行顺序。
	- 主要分为三个阶段(与上图对应):

1. 捕获阶段: 从文档的最底层(document)向上查询事件源,直到查询到事件源,这段时间都是捕获阶段(①~④);
2. 目的阶段: 捕获阶段改变至冒泡阶段的时段(④);
3. 冒泡阶段(处理事件的阶段): 由事件源向下冒泡,直到冒泡文档(document)之后,冒泡结束(④~⑦)。

give a chestnut

Take a simple example of click to illustrate:

<!DOCTYPE html>
<html lang="en" onclick="clickHandle('html', event)">
<head>
  <style>
    #app {
      
      
      background-color: red;
      color: #ccc;
    }
  </style>
</head>

<body onclick="clickHandle('body', event)">
  <div id="app" onclick="clickHandle('#app', event)">
    <button onclick="clickHandle('button', event)">按钮</button>
  </div>
</body>

<script>
  function clickHandle(msg, e) {
      
      
    console.log(`\`${ 
        msg}\` 被点击了`, e);
  }
</script>
</html>
/**
   * 上面的代码主要是给 'html' > 'body' > '#app' > 'button', 添加了一个点击事件 'click',对应的DOM事件触发后会console一条提示信息;
   * 
   * 而根据我们上面说明的事件流向的话:
   *  - 当我们点击了 <button> 按钮,我们的console顺序应该是: 
   *    1. 捕获阶段: html -> body -> #app -> button 
   *    2. 目标阶段:button
   *    3. 冒泡阶段:button -> #app -> body -> html
   * html -> body -> #app -> button -> button -> button -> #app -> body -> html (除button外,每个dom触发两次)
  **/

Execute 100 million times
insert image description hereinsert image description here
to output four sentences! ? impossible! ! The code I wrote must be correct! ! !
Spam browser! Gan! ! !

Browser Default Event Behavior

其实很简单就能想通了。
- 要是事件流的每一步都触发,那每一个dom事件都要触发两次至少,但是普遍我们只需要一次;
- 所以这里的话浏览器普遍默认的是只执行事件流的  '冒泡阶段';
- 能解(忽)释(悠)通了
- 事实就是这样的

trigger capture phase

如果需要我们的事件在捕获阶段就触发呢:
这个时候就需要用到 ‘addEventListener’ ,设置第三个参数当为 true 时,就触发于捕获阶段;
那我们在给每一个DOM添加一个;
<!DOCTYPE html>
<html lang="en" onclick="clickHandle('html', event)">

<head>
  <style>
    #app {
      
      
      background-color: red;
      color: #ccc;
    }
  </style>
</head>

<body onclick="clickHandle('body', event)">
  <div id="app" onclick="clickHandle('#app', event)">
    <button onclick="clickHandle('button', event)">按钮</button>
  </div>
</body>

<script>
  function clickHandle(msg, e) {
      
      
    console.log(`\`${ 
        msg}\` 被点击了`, e);
  }

  document.querySelector("button").addEventListener('click', (e) => clickHandle('capture: button', e), true);
  document.querySelector("#app").addEventListener('click', (e) => clickHandle('capture: #app', e), true);
  document.querySelector("body").addEventListener('click', (e) => clickHandle('capture: body', e), true);
  document.querySelector("html").addEventListener('click', (e) => clickHandle('capture: html', e), true);
</script>

</html>

Run it:
insert image description here
it works
, but there is a small problem that needs to be noticed. The above is the result of running Google Chrome; the
following is the result of running QQ Browser, Firefox, and Google Dual-Core Browser.
insert image description here
Finally, there are some small differences in the target element, but Not a big problem (keep an eye out).

Possible problems on the project (cancel the browser's default behavior)

  • Nesting of elements; such as nuts in our example, no no. . .
  • For example, in our example, clicking the button only requires console, and clicking #app requires only alert;
  • But if written as above,
  • When clicking #app, it is correct;
  • When the button is clicked, console + alert will appear (bubble event triggered) something went wrong! ! !
  • At this time, we don't need the button to trigger the bubbling event; so we need to cancel the browser's default behavior;
// 阻止冒泡事件
    if (e.stopPropagation) {
    
    
      e.stopPropagation()
    } else {
    
    
      e.cancelBubble = true; // 兼容 IE8-
    }
// vue的话,使用修饰符就可以了 https://cn.vuejs.org/v2/api/#v-on
// <button @click.stop="btnClick">按钮</button>

all codes

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    #app {
      
      
      background-color: red;
      color: #ccc;
    }
  </style>
</head>

<body>

  <div id="app">
    <button>按钮</button>
  </div>
</body>

<script>
  let appDom = document.getElementById("app");
  let btnDom = document.querySelector("button");

  appDom.addEventListener('click', appClick);
  btnDom.addEventListener('click', btnClick);

  function btnClick(e) {
      
      
    e.stopPropagation(); // 马上2022了,微软都自己放弃ie了,就不要让它来祸害我们前端了。。。
    console.log('btn 被点击了')
  }

  function appClick() {
      
      
    alert("app 被点击了");
  }
</script>

</html>

Guess you like

Origin blog.csdn.net/cc_King/article/details/121283807