事件传播机制和事件委托

DOM事件流

  • DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
  • 事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。
  • 事件冒泡(dubbed bubbling):与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。
  • 无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播.

事件传播机制

  1. 层级结构:window -> document -> html -> body -> root ->outer -> inner
  2. ev.stopPropagation:阻止事件的传播(包含捕获和冒泡),同级的不会阻止
  3. ev.stopImmediatePropagation:也是阻止事件传播,只不过它可以把当前元素绑定的其它方法(同级的),如果还未执行,也不会让其在执行了!

我们通过代码来看一下

复制代码
const html = document.documentElement,
        body = html.body,
        root = document.querySelector("#root"),
        outer = document.querySelector("#outer"),
        inner = document.querySelector("#inner");

      //事件传播机制

      root.addEventListener(
        "click",
        function (ev) {
          //   ev.stopPropagation(); //也能阻止捕获
          console.log("root 捕获");
        },
        true
      );

      root.addEventListener(
        "click",
        function () {
          console.log("root 冒泡");
        },
        false
      );

      outer.addEventListener(
        "click",
        function () {
          console.log("outer 捕获");
        },
        true
      );

      outer.addEventListener(
        "click",
        function () {
          console.log("outer 冒泡");
        },
        false
      );

      inner.addEventListener(
        "click",
        function () {
          console.log("inner 捕获");
        },
        true
      );
      inner.addEventListener(
        "click",
        function (ev) {
          console.log("inner 冒泡0");
        },
        false
      );

让我们一起画个图来了解这个事件传播机制

再通过代码来了解一下ev.stopPropagation,ev.stopImmediatePropagation的区别,在上面的代码增加

1.使用ev.stopImmediatePropagation

复制代码
 inner.addEventListener(
        "click",
        function (ev) {
          //   ev.stopPropagation(); //阻止冒泡传播
          ev.stopImmediatePropagation(); //立即阻止冒泡传播 往下也不继续 往上也不继续执行了
          console.log("inner 冒泡1");
        },
        false
      );
      inner.addEventListener(
        "click",
        function (ev) {
          console.log("inner 冒泡2");
        },
        false
      );

2.使用ev.stopPropagation

复制代码
inner.addEventListener(
        "click",
        function (ev) {
          ev.stopPropagation(); //阻止冒泡传播
          // ev.stopImmediatePropagation(); //立即阻止冒泡传播 往下也不继续 往上也不继续执行了
          console.log("inner 冒泡1");
        },
        false
      );
      inner.addEventListener(
        "click",
        function (ev) {
          console.log("inner 冒泡2");
        },
        false
      );

事件委托

事件委托:利用事件的传播机制,实现的一套事件绑定处理方案

需求例如: 一个容器中,有很多元素都要在点击的时候做一些事情

      • 传统方案:首先获取需要操作的元素,然后逐一做事件绑定。
      • 事件委托: 只需要给容器做一个事件绑定(点击内部的任何元素,根据事件的冒泡传播机制,都会让容器的点击事件也触发,我们在这里根据事件源做不同的事情就可以了

最重要的:ev.target:事件源(根据事件源做不同的事情)

复制代码
 const body = document.body;
      body.addEventListener("click", function (ev) {
        //ev.target:事件源,(点击的是谁就是谁)
        console.log("ev", ev.target);
        let target = ev.target,
          id = target.id;
        if (id === "root") {
          console.log("root");
          return;
        }
        if (id === "outer") {
          console.log("outer");
          return;
        }
        if (id === "inner") {
          console.log("inner");
          return;
        }
        //如果以上都不是,我们处理别的逻辑
        console.log("哈哈哈");
      });

事件委托的优劣势

优势:

1.提高JS代码运行的性能,并且把处理的逻辑都集中在一起!!

2.某些需求必须基于事件委托处理,例如:除了点击XXX外,点击其余的任何东西,都显示对应的处理逻辑

3.给动态绑定的元素做事件绑定

劣势:

1.当前操作事件必须支持冒泡传播机制才可以(例如:mouseenter/mouseleave等事件是没有冒泡传播机制的)

2.如果单独做的事件绑定中,做了事件传播机制的阻止,那么事件委托中的操作也不会生效

相关推荐
生戎马 平安京策22 分钟前
只学一点点:我的技术学习策略
前端·javascript·react.js
得物技术3 小时前
实战从零开始构建一个Coding Agent:Violin |得物技术
javascript·架构·llm
JiaLin_Denny4 小时前
Vue3中ref和reactive用法与双向数据绑定
前端·javascript·vue.js
wear工程师4 小时前
React 的 key 为什么不能随手用 index:一插入列表,状态就串了
javascript·react.js
嘟嘟07174 小时前
一文讲通 SPA 前端路由:从传统多页到手写 HashRouter
javascript
柒和远方4 小时前
V058:前端路由的第一性原理:从 hashchange 手写路由,到 React Router 的嵌套与懒加载
前端·javascript·react.js
冷咖啡离 我的笨笨4 小时前
通过(Node Js||.Net)基于HTML5的WebSocket实现实时视频文字传输(上)
javascript·.net·html5
冰暮流星4 小时前
javascript练习之string
开发语言·javascript·ecmascript
张元清4 小时前
桶文件(Barrel Files):index.ts 统一导出如何拖垮 Tree Shaking、Next.js 开发内存和 tsc
javascript·react.js
名字还没想好☜4 小时前
React useImperativeHandle 实战:让父组件安全地调用子组件的方法
前端·javascript·react.js·react·forwardref