zoukankan      html  css  js  c++  java
  • JS事件冒泡机制和兼容性添加事件

    本篇文章主要来讲讲 事件的冒泡机制 和 添加事件的几种方法。


    一. JS的事件传递顺序: 捕获阶段 -> 目标阶段 -> 冒泡阶段

    • 捕获阶段是指从父层往子层找。比如 <body><div></div></body> ,我们会先找到 body,然后下一个才是 div。就像中央领导发布政策一样。 从上往下通知。

    • 目标阶段就是找到目标的那段时间,这个我们暂且不谈。

    • 冒泡阶段就是从子层往外层传。比如 <body><div></div></body> ,这个时候是先写 div ,再找 body。往外依次冒泡。从内往外通知。

      先从外到内传一圈波纹,再从内到外传一圈波纹

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Document</title>
      </head>
      <body>
        <div id="div2">
          <div id="div1">
            点我
          </div>
        </div>
      </body>
      <script type="text/javascript">
        const oBtn = document.getElementById('div1')
        const div1 = document.getElementById('div1')
        const div2 = document.getElementById('div2')
        // addEventListener 的第三个参数默认为 false —— 表示该事件在冒泡阶段触发; true 则表示在捕获阶段触发
        div1.addEventListener('click', function (event) {
          console.log("A");
        }, true);
        div2.addEventListener('click', function (event) {
          console.log("B");
        });
        div1.addEventListener('click', function (event) {
          console.log("C")
        }, false);
        div2.addEventListener('click', function (event) {
          console.log("D");
        }, true);
      </script>
      </html>
      

    答案是: DACB

    根据 JS 的 dom 事件顺序 ———— “从外到内,从内到外” 和 addEventListener第三个参数所控制的触发阶段我们可以很容易地解答。

    • 1.div2 在外面,div1 在里面。捕获阶段时优先;掠过 div2 后再掠过 div1,发现他们要找的人是 D 和 A (因为第三个参数为true)
    • 2.然后到了 冒泡阶段;掠过 div1 后途经 div2;他们要找的分别是捆绑在 div1 上的 C 然后是 B。

    二. 兼容性地添加 JS 事件

    如果我们要给按钮添加事件,我们会怎么做呢?

    也许我们会这么做<button onclick="console.log('1')">点我</button>
    很明显地,它破坏了标签。我们应该让 html 和 事件分离,否则,我们下一次要修改这个按钮就不好操作了。
    他有个致命的缺点:那就是只能用此方法添加一个事件,后面的会覆盖前面(原理是指向了不同的对象)。

    • 错误示范:
        const oBtn = document.getElementsByTagName('button')[0];
        oBtn.onclick = function() {
          console.log('1');
        }
        // 只会显示下面这次
        oBtn.onclick = function() {
          console.log('我是第二次');
        }
      
    • 正确示范:
        const oBtn = document.getElementsByTagName('button')[0];
        // addEventListener
        oBtn.addEventListener("click", () => {console.log('1')});
        oBtn.addEventListener("click", () => {console.log('我是第二次')} );
        // 上面的两次都会被认可
      

    我们已经决定放弃(不推荐)使用 onclick;但接下来还有一件事情要做,那就是兼容性问题。

    事件并不总是如我们所想的运转,感觉失望和沮丧是徒劳无益的,我们要想办法改变我们自己适应这个世界。

    IE 6/7/8 上并没有 addEventListener.它们使用了特殊的 attachEvent;对于这样的少数人,我们也不能完全放弃。

    代码的健壮性是锦上添花还是...至关重要的?也许这是裁定程序员优秀的标准吧。
    遂改成这样。(可以在老IE和Chrome上感受一下差距)

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
    </head>
    <body>
      <div id="div2" style="border: 1px solid #089e8a;padding: 10px;">
        <div id="div1" style="border: 1px solid blue;padding: 10px;">
          点我
        </div>
      </div>
    </body>
    <script type="text/javascript">
      var oBtn = document.getElementById('div1')
      var div1 = document.getElementById('div1')
      var div2 = document.getElementById('div2')
      // 注意:attachEvent 只有冒泡没有捕获!!!
      var addEvent = function (dom, eventType, method, isBubble) {
        eventType = eventType || 'click'
        isBubble = isBubble || false
        if (dom.addEventListener) {
          dom.addEventListener(eventType, method, isBubble)
        } else if (dom.attachEvent) {
          dom.attachEvent('on' + eventType, method)
        }
      }
      var methodX = function () {
        console.log('methodX')
      }
      var method2 = function () {
        console.log('method2')
      }
      addEvent(div1, 'click', methodX)
      addEvent(div2, 'click', method2)
    </script>
    </html>
    

    除此之外我们还想要知道的 addEventListener 和 attachEvent 都是讲究规则的。谁先来,谁在上面。

      // 多个 addEventListener 的执行顺序:谁先被添加,谁就在前面
      div1.addEventListener('click', event => {
        console.log('first')
      })
      div1.addEventListener('click', event => {
        console.log('second')
      })
      div1.addEventListener('click', event => {
        console.log('third')
      })
    

    complete

  • 相关阅读:
    动态规划
    关键路径
    拓扑排序
    最小生成树
    Floyd 多源最短路径
    SPFA算法
    Bellman_Ford算法(负环的单源路径)
    Dijkstra算法
    fill和memset的区别
    Codeforces Round #655 (Div. 2) 题解
  • 原文地址:https://www.cnblogs.com/can-i-do/p/7412298.html
Copyright © 2011-2022 走看看