最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 关于事件捕获与事件冒泡先后执行顺序

    正文概述 掘金(豆包君)   2021-02-23   982

    @关于事件捕获与事件冒泡先后执行顺序

    目录

    • 前言

    • 正文

    • 总结

    前言

     作为一名前端开发,DOM是我们最熟悉的伙伴之一——每天F11都能看到它。

     但是,你真的懂它吗?能描述一下事件捕获与事件冒泡先后执行顺序吗?

     如果一时想不起来,我们就去看一下吧。

    正文

    DOM 事件流的三个阶段

     事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM 事件流

     当一个 DOM 事件被触发时,它不仅仅只是单纯地在本身对象上触发一次,而是会经历三个不同的阶段:

    1. 捕获阶段(Capture Phase):
    • 当我们在 DOM 树的某个节点发生了一些操作(例如单击、鼠标移动上去),就会有一个事件发射过去。这个事件从 Window 发出,不断经过下级节点直到触发的目标节点。在到达目标节点之前的过程,就是捕获阶段(Capture Phase)。(所有经过的节点,都会触发这个事件。捕获阶段的任务就是建立这个事件传递路线,以便后面冒泡阶段顺着这条路线返回 Window。)在目标元素对象本身上注册的捕获事件处理程序不会被调用。
    1. 目标阶段(Target Phase):
    • 当事件不断的传递直到目标节点的时候,最终在目标节点上触发这个事件,就是目标阶段。
    1. 冒泡阶段(Bubbling Phase):
    • 再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象(我们平时用的事件绑定就是利用的事件冒泡的原理)

    如图所示:

    关于事件捕获与事件冒泡先后执行顺序

     事件捕获与事件冒泡先后执行顺序就显而易见了。

    DOM 元素绑定 js 事件方式:

    onclick

     在 html 标签里面或通过赋值的方式创建onclick事件 ,重写onclick会覆盖之前的属性,只支持冒泡阶段,不存在兼容性问题

    绑定事件:element.onclick = function(){}

    解绑事件:element.onclick = null

    addEventListener

     IE8 以下不支持,属于 DOM2 级方法,可以添加多个方法不被覆盖

    参数说明:

    • event,必须。字符串,指定事件名。 不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。

    • function 必须。指定要事件触发时执行的函数,注意只写函数名,不要带括号。

    • useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。

    绑定事件:

    element.addEventListener(
      'click',
      function (e) {
        e.preventDefault() //阻止默认事件
      },
      false
    )
    

    解绑事件:

    element.removeEventListener('click',function(){},false)

    attachEvent

     IE 特有,兼容 IE8 及以下版本,可添加多个事件处理程序,只支持冒泡阶段

    参数说明:

    • event,必须。字符串,指定事件名。注意加上事件前边的“on”,比如“onclick”和“onmouseover”,这是与 addEventListener 的区别。
    • function 要绑定的事件监听函数,注意只写函数名,不要带括号。

    绑定事件:

    element.attachEvent('onclick', function (e) {
      e.returnValue = false //阻止默认事件
    })
    

    解绑事件: element.detachEvent("onclick",function(){})

    上代码,做实验

     打开在线编辑器 ---> jsbin.com/cedorat/edi…

    代码如下:

    </html>
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <style>
        #outer {
          text-align: center;
          width: 400px;
          height: 400px;
          background-color: yellow;
          margin: 0 auto;
        }
    
        #middle {
          width: 250px;
          height: 250px;
          background-color: red;
          margin: 0 auto;
        }
    
        #inner {
          width: 100px;
          height: 100px;
          background-color: green;
          margin: 0 auto;
        }
      </style>
    </head>
    
    <body>
      <div id='outer'>
        <span>outer</span>
        <div id='middle'>
          <span>middle</span>
          <div id='inner'>
            <span>inner</span>
          </div>
        </div>
      </div>
      <script>
        // 先全部绑定捕获事件再全部绑定冒泡事件
        on("outer", "click", o_click_c, true);
        on("middle", "click", m_click_c, true);
        on("inner", "click", i_click_c, true);
    
        on("outer", "click", o_click_b, false);
        on("middle", "click", m_click_b, false);
        on("inner", "click", i_click_b, false);
    
    
        // // 先全部绑定冒泡事件再全部绑定捕获事件
        // on("outer", "click", o_click_b, false);
        // on("middle", "click", m_click_b, false);
        // on("inner", "click", i_click_b, false);
    
        // on("outer", "click", o_click_c, true);
        // on("middle", "click", m_click_c, true);
        // on("inner", "click", i_click_c, true);
    
    
        // 挨个绑定捕获及冒泡事件
        // on("outer", "click", o_click_c, true);
        // on("outer", "click", o_click_b, false);
    
        // on("middle", "click", m_click_c, true);
        // on("middle", "click", m_click_b, false);
    
        // on("inner", "click", i_click_c, true);
        // on("inner", "click", i_click_b, false);
    
    
        // 挨个绑定冒泡及捕获事件
        // on("outer", "click", o_click_b, false);
        // on("outer", "click", o_click_c, true);
    
        // on("middle", "click", m_click_b, false);
        // on("middle", "click", m_click_c, true);
    
        // on("inner", "click", i_click_b, false);
        // on("inner", "click", i_click_c, true);
    
    
        // 选择相应元素
        function $(element) {
          return document.getElementById(element);
        }
        // 绑定方法
        function on(element, event_name, handler, use_capture) {
          if (addEventListener) { //所有主流浏览器,除了 IE 8 及更早 IE版本
            $(element).addEventListener(event_name, handler, use_capture);
          } else { // IE 8 及更早 IE 版本
            $(element).attachEvent('on' + event_name, handler);
          }
        }
    
        function o_click_c() {
          console.log("outer_捕获");
        }
    
        function m_click_c() {
          console.log("middle_捕获")
        }
    
        function i_click_c() {
          console.log("inner_捕获")
        }
    
        function o_click_b() {
          console.log("outer_冒泡")
        }
    
        function m_click_b() {
          console.log("middle_冒泡")
        }
    
        function i_click_b() {
          console.log("inner_冒泡")
        }
      </script>
    </body>
    
    </body>
    
    </html>
    

     在上述代码中,我们定义了四种执行顺序:

    1. 先全部绑定捕获事件再全部绑定冒泡事件

    2. 先全部绑定冒泡事件再全部绑定捕获事件

    3. 挨个绑定捕获及冒泡事件

    4. 挨个绑定冒泡及捕获事件

    一、先全部绑定捕获事件再全部绑定冒泡事件

    我们先运行第一种:

    1. 点击 outer,打印结果:
    "outer_捕获"
    "outer_冒泡"
    
    1. 点击 middle,打印结果:
    "outer_捕获"
    "middle_捕获"
    "middle_冒泡"
    "outer_冒泡"
    
    1. 点击 inner,打印结果:
    "outer_捕获"
    "middle_捕获"
    "inner_捕获"
    "inner_冒泡"
    "middle_冒泡"
    "outer_冒泡"
    

    结论:

    • 先由外向内事件捕获,一直到事发元素,再由内向外冒泡到根节点上

    二、先全部绑定冒泡事件再全部绑定捕获事件

    我们先运行第二种:

    1. 点击 outer,打印结果:
    "outer_冒泡"
    "outer_捕获"
    
    1. 点击 middle,打印结果:
    "outer_捕获"
    "middle_冒泡"
    "middle_捕获"
    "outer_冒泡"
    
    1. 点击 inner,打印结果:
    "outer_捕获"
    "middle_捕获"
    "inner_冒泡"
    "inner_捕获"
    "middle_冒泡"
    "outer_冒泡"
    

    结论:

    • 在捕获阶段先由外向内事件捕获,在冒泡阶段由内向外冒泡到根节点上

    • 目标元素先执行冒泡事件,再执行捕获事件

    三、挨个绑定捕获及冒泡事件

    我们先运行第三种:

    1. 点击 outer,打印结果:
    "outer_捕获"
    "outer_冒泡"
    
    1. 点击 middle,打印结果:
    "outer_捕获"
    "middle_捕获"
    "middle_冒泡"
    "outer_冒泡"
    
    1. 点击 inner,打印结果:
    "outer_捕获"
    "middle_捕获"
    "inner_捕获"
    "inner_冒泡"
    "middle_冒泡"
    "outer_冒泡"
    

    结论:

    • 同第一种一样,先由外向内事件捕获,一直到事发元素,再由内向外冒泡到根节点上

    四、挨个绑定冒泡及捕获事件

    我们先运行第四种:

    1. 点击 outer,打印结果:
    "outer_冒泡"
    "outer_捕获"
    
    1. 点击 middle,打印结果:
    "outer_捕获"
    "middle_冒泡"
    "middle_捕获"
    "outer_冒泡"
    
    1. 点击 inner,打印结果:
    "outer_捕获"
    "middle_捕获"
    "inner_冒泡"
    "inner_捕获"
    "middle_冒泡"
    "outer_冒泡"
    

    结论:

    同第二种一样

    • 在捕获阶段先由外向内事件捕获,在冒泡阶段由内向外冒泡到根节点上

    • 目标元素先执行冒泡事件,再执行捕获事件

    总结

    事件流执行顺序

     通过以上代码,我们可以看出,关于事件捕获与事件冒泡先后执行顺序:

    1. 在捕获阶段,先由外向内执行捕获事件

    2. 当事件触发在目标阶段时,会根据事件注册的先后顺序执行。也就是说如果该处既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行

    3. 在冒泡阶段,由内向外冒泡到根节点上

    其他:

    1. js 代码只能执行捕获或者冒泡其中一个阶段(要么是捕获要么是冒泡)

    2. onclick 和 attachevent(ie)只能得到冒泡阶段

    3. 实际开发中,我们很少使用事件捕获,我们更关注事件冒泡

    4. 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave

    5. 事件的冒泡有时会带来麻烦,不过是可以被阻止的,方法是:stopPropagation()

    • stopPropagation() 方法:终止事件在传播过程的捕获、目标处理或冒泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。

     路漫漫其修远兮,与诸君共勉。

    参考文献:

    • JS阻止冒泡和取消默认事件(默认行为) | 前端开发博客
    • JavaScript捕获和冒泡探讨 | 前端开发博客
    • DOM事件阶段以及事件捕获与事件冒泡先后执行顺序 | 博客园 - AlvinWei

    后记:Hello 小伙伴们,如果觉得本文还不错,记得点个赞或者给个 star,你们的赞和 star 是我编写更多更丰富文章的动力!GitHub 地址

    文档协议


    起源地下载网 » 关于事件捕获与事件冒泡先后执行顺序

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元