02_事件冒泡及事件捕获

参考资料:
理解事件冒泡和事件捕获
终于弄懂了事件冒泡和事件捕获!
JS阻止事件冒泡和默认事件

红皮书:

在第四代 Web 浏览器(IE4 和 Netscape Communicator 4)开始开发时,开发团队碰到了一个有意思的问题:页面哪个部分拥有特定的事件呢?

  • 要理解这个问题,可以在一张纸上画几个同心圆。把手指放到圆心上,则手指不仅是在一个圆圈里,而且是在所有的圆圈里。两家浏览器的开发团队都是以同样的方式看待浏览器事件的。当你点击一个按钮时,实际上不光点击了这个按钮,还点击了它的容器以及整个页面。事件流描述了页面接收事件的顺序。
  • 结果非常有意思,IE 和 Netscape 开发团队提出了几乎完全相反的事件流方案。IE 将支持事件冒泡流,而 Netscape Communicator 将支持事件捕获流。

事件冒泡: IE事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。
事件捕获: Netscape Communicator 团队提出了另一种名为事件捕获的事件流。事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。

十分恰当的比喻: 当你把一个可以漂浮在水面上的物品,使劲向水里砸下去,它会首先有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后由于浮力大于物体自身的重力,物体会在到达最低点( 最具体元素)之后漂浮到水面上,这个过程相对于事件捕获是一个回溯的过程,即事件冒泡。

实例:

<body>
  <div id="div-01">
    start!
    <h3 id="h3-01">hello</h3>
    <h3 id="h3-02">world</h3>
  </div>
</body>
<script>
  let div = document.getElementById('div-01')
  let h_1 = document.getElementById('h3-01')
  let h_2 = document.getElementById('h3-02')
  // 设置h_1、h_2为默认事件(事件冒泡)
  h_1.addEventListener('click', function () {
    console.log('hello')
  })
  h_2.addEventListener('click', function () {
    console.log('world')
  })
  // 设置div为事件捕获,点击hello,预期输出:start!hello
  // div.addEventListener(
  //   'click',
  //   function () {
  //     console.log('start!')
  //   },
  //   true
  // )
  // 设置div为事件冒泡,点击world,预期输出:world start!
  div.addEventListener(
    'click',
    function () {
      console.log('start!')
    },
    false
  )
</script>

注意点:

  1. addEventListener的第三个参数决定了是事件捕获还是事件冒泡
    true:表示注册的事件在捕获阶段触发
    false:表示注册的事件在冒泡阶段触发-----默认值

  2. 误解:元素并不是只有注册了事件,才会有事件冒泡和事件捕获

  3. 事件流三个阶段; 1.事件捕获 2.目标事件[事件源] 3.事件冒泡

  4. 一个元素的事件,不会在两个阶段都触发

额外知识点: 阻止事件冒泡和默认事件

<body>
  <div id="info">
    <div class="box-1" οnclick="box1()">
      最外层
      <div class="box-2" οnclick="box2()">
        第二层
        <div class="box-3" οnclick="box3()">
          第三层
          <div class="box-4" οnclick="bubbles()">最底层</div>
        </div>
      </div>
    </div>
  </div>
</body>
<script>
  function bubbles() {
    console.log('最底层盒子被点击了')
  }
  function box1() {
    console.log('最外层盒子被点击了')
  }
  function box2() {
    console.log('第二个盒子被点击了')
  }
  function box3() {
    console.log('第三个盒子被点击了')
  }
</script>

阻止冒泡事件(最底层):

<script>
  function bubbles(e) {
    var ev = e || window.event
    if (ev && ev.stopPropagation) {
      //非IE浏览器
      ev.stopPropagation()
    } else {
      //IE浏览器(IE11以下)
      ev.cancelBubble = true
    }
    console.log('最底层盒子被点击了')
  }
</script>

阻止默认事件的方式:

//谷歌及IE8以上
e.preventDefault();
//IE8及以下
window.event.returnValue = false;
//无兼容问题(但不能用于节点直接onclick绑定函数)
return false;

实例:

<body>
  <div id="info">
    <a href="www.baidu.com" id="test">阻止默认事件</a>
  </div>
</body>
<script>
  var aDom = document.getElementById('test')
  aDom.onclick = function (e) {
    if (e && e.preventDefault) {
      //非IE浏览器
      e.preventDefault()
    } else {
      //IE浏览器(IE11以下)
      window.event.returnValue = false
    }
    //return false;   //或者不写上面的判断直接写这句
  }
</script>

使用return false注意点:

<body>
  <div id="info">
    <a href="www.baidu.com" οnclick="defaultEvent()">阻止默认事件</a>
  </div>
</body>
<script>
  function defaultEvent() {
    return false
  }
</script>

无法通过这个函数阻止a标签的跳转,return false不能适用于直接用onclick绑定的事件,所以当我们使用这种绑定事件方式时,我们还是需要采用e.preventDefault()这个函数

写在最后:return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值