Dom的事件模型、事件冒泡、阻止冒泡和事件委托

什么是事件模型

Dom标准的事件模型:当事件发生时,其实会经历三个阶段!

  1. 由外向内的捕获阶段:从Dom树根节点开始,到当前点击的元素位置,遍历并记录当前元素各级父元素上绑定的事件处理函数,这个阶段只是记录并不触发。
  2. 目标触发阶段:优先触发当前点击元素的处理函数
  3. 冒泡执行阶段:按捕获阶段记录的各个父元素上的事件处理函数顺序,由内到外的反向的触发各级父元素上的事件

如图所示
在这里插入图片描述
看个例子

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    #d1 #d2 #d3 {
      cursor: pointer;
    }

    #d1 {
      background-color: green;
      position: relative;
      width: 150px;
      height: 150px;
      text-align: center;
      cursor: pointer;
    }

    #d2 {
      background-color: blue;
      position: absolute;
      top: 25px;
      left: 25px;
      width: 100px;
      height: 100px;
    }

    #d3 {
      background-color: red;
      position: absolute;
      top: 25px;
      left: 25px;
      width: 50px;
      height: 50px;
      line-height: 50px;
    }
  </style>
  <body>
    <div id="d1">
      1
      <div id="d2">
        2
        <div id="d3">3</div>
      </div>
    </div>
  </body>
</html>

网页效果图
在这里插入图片描述
如果我在每个div上绑定一个点击事件,点到谁就弹窗内容为疼,JavaScript代码如下:

<script>
var d1=document.getElementById("d1");
var d2=document.getElementById("d2");
var d3=document.getElementById("d3");
      //本意: 点谁,谁就喊疼!
      d1.onclick=function(){
        alert("d1疼!");
      }
      d2.onclick=function(){
        alert("d2疼!");
      }
      d3.onclick=function(){
        alert("d3疼!");
      }
</script>

需求是点1绿色的div应该只弹出“d1疼”,点2蓝色的div应该只弹出“d2疼”,点3红色的div应该只弹出“d3疼”。
但是由于事件模型是冒泡执行的,如果点2蓝色的,就会弹出“d2疼”和“d1疼”。这样就导致了事件冒泡。

阻止冒泡/停止蔓延

使用事件对象中的stopPropagation()方法,来阻止冒泡/停止蔓延。e.stopPropagation()防的是父元素上处理函数的执行,而不是防当前元素自己的处理函数
所以想要实现点是谁才谁弹窗,如下代码。

<script>
      var d1=document.getElementById("d1");
      var d2=document.getElementById("d2");
      var d3=document.getElementById("d3");
      //本意: 点谁,谁就喊疼!
      //当事件发生时     event
      //                  ↓
      d1.onclick=function(e){
        //e.stopPropagation() //因为d1外边没有可执行的处理函数了
        alert("d1疼!");
      }
      d2.onclick=function(e){
        //e.stopPropagation() //都行
        alert("d2疼!");
        e.stopPropagation() //都行
      }
      d3.onclick=function(e){
        e.stopPropagation()
        alert("d3疼!");
      }
</script>

这样就实现了我们需求了。
但是,冒泡这种机制到底好不好?如果不好为什么事件模型默认的就是冒泡呢?接下来我们看看冒泡的作用

事件委托/代理

什么是事件委托

如果多个平级子元素都要绑定相同的事件时,应该只给父元素绑定一次事件,所有子元素可通过冒泡机制共用父元素上的一个事件处理函数!

为什么要用事件委托

因为浏览器触发事件,是通过遍历事件监听队列的凡是查找符合条件的监听对象触发的。如果事件监听对象很多!遍历就会慢,导致事件响应变慢,

如何使用事件委托呢?我们用一个简单的手风琴为例子

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    ul {
      list-style: none;
    }
    li:first-child {
      border-top-left-radius: 7px;
      border-top-right-radius: 7px;
    }
    li:nth-child(7) {
      border-bottom-left-radius: 7px;
      border-bottom-right-radius: 7px;
    }
    li {
      width: 200px;
      height: 50px;
      line-height: 50px;
      border: 1px solid #ddd;
      background-color: #fff;
    }
    .none {
      display: none;
    }
    .block {
      display: block;
    }
  </style>
  <body>
    <ul>
      <li>手风琴1</li>
      <span class="none">手风琴1的内容</span>
      <li>手风琴2</li>
      <span class="none">手风琴2的内容</span>
      <li>手风琴3</li>
      <span class="none">手风琴3的内容</span>
      <li>手风琴4</li>
      <span class="none">手风琴4的内容</span>
    </ul>

    <script>
      var ul = document.querySelector("ul");   //获取父元素
      //给父元素绑定一个点击事件
      ul.onclick = function (e) {
        //e.target专门保存最初点击的目标元素的特殊属性。一旦保存住最初点击的目标元素,就不会随冒泡而改变!
        if (e.target.nodeName == "LI") {
          var span = e.target.nextElementSibling;
          var b_span = document.querySelector(".block");
          if (span.className == "block") {
            span.className = "none";
          } else {
            if (b_span != null) {
              b_span.className = "none";
              span.className = "block";
            }
            span.className = "block";
          }
        }
      };
    </script>
  </body>
</html>

效果如下

效果 1效果 2效果3
在这里插入图片描述在这里插入图片描述在这里插入图片描述

将子元素触发相同的事件处理函数绑定在父元素身上,通过事件冒泡来获取触发事件函数,使用e.target来指向当前点击的元素,使当前点击的元素能够触发该事件。这就是事件委托

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值