DOM事件体系:事件流、事件对象、事件代理


事件流

事件流表示的是事件在页面中传播的顺序,现代浏览器都遵从一套通用的事件流标准,包括 捕获流冒泡流

事件与事件监听

  • 事件

事件描述的是发生在浏览器里的动作,这个动作可以由用户从外部触发,也可以是浏览器内部逻辑触发。

  • 事件监听函数
document.addEventListener(event, function, useCapture)

event: 事件类型,像点击(click)、鼠标悬停(mouseover)、鼠标移走(mousemove)等。
function: 事件触发后执行的函数
useCapture: 事件的执行时机 :

  • false: 默认, 事件在冒泡阶段执行 ;
  • true: 事件在捕获阶段执行

事件捕获、事件冒泡

为了方便的表示事件在元素中的两种传递方式,我们新建如下html页面

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    #out{
      background-color: red;
      width:300px;
      height: 300px;
    }
    #middle{
      background-color: green;
      width:200px;
      height: 200px;
    }
    #in{
      background-color: blue;
      width:100px;
      height: 100px;
    }
  </style>
</head>

<body>

  <div id="out">
    <div id="middle">
      <div id="in">
      </div>
    </div>
  </div>

  <script>
  
  </script>
</body>

</html>

在这里插入图片描述

当事件被触发时,首先经历捕获流:事件会从最外层的元素开始逐元素到目标元素;然后事件从目标元素原路返回,进入到冒泡流—— 逐个元素冒到最外层。

在这里插入图片描述

  • 事件冒泡
    为三个div逐个注册事件,addEventListener 的第三个参数设置为false(默认值),开启事件冒泡流:
 <script>

    const div_out = document.getElementById('out')
    const div_middle = document.getElementById('middle')
    const div_in = document.getElementById('in')
    
    // 事件冒泡流
    div_out.addEventListener('click', function(){
      console.log('冒泡----div_out--red')
    }, false)

    div_middle.addEventListener('click', function(){
      console.log('冒泡----div_middle--green')
    }, false)

    div_in.addEventListener('click', function(){
      console.log('冒泡----div_in--blue', )
    }, false)
  </script>

点击蓝色区域,输出如下👇
在这里插入图片描述

  • 事件捕获
    为三个div逐个注册事件,addEventListener 的第三个参数设置为true,开启事件捕获流:
 <script>

    const div_out = document.getElementById('out')
    const div_middle = document.getElementById('middle')
    const div_in = document.getElementById('in')
    
    // 事件捕获流
    div_out.addEventListener('click', function(){
      console.log('捕获----div_out--red')
    }, true)

    div_middle.addEventListener('click', function(){
      console.log('捕获----div_middle--green')
    }, true)

    div_in.addEventListener('click', function(){
      console.log('捕获----div_in--blue', )
    }, true)
  </script>

同样是点击蓝色区域,输出如下👇

在这里插入图片描述

事件对象

当 DOM 事件处理函数触发时,就会产生一个事件对象 event 作为处理函数的入参。这个对象中囊括了与事件有关的信息,比如事件具体是由哪个元素所触发、鼠标点击位置,触发事件的元素对象等。

    div_in.addEventListener('click', function(e){
      console.log('捕获----div_in--blue', e)
    }, true)

事件对象的属性

在 event 上有两个重要的属性 currentTargettarget

在这里插入图片描述

  • currentTarget :记录事件当下正在被哪个元素接收
  • target :指触发事件的具体目标,即事件的真正来源。

事件对象的方法

除此之外,在事件对象的原型链向上寻找,还有两个非常重要的方法 preventDefaultstopPropagation

在这里插入图片描述

  • preventDefault :阻止特定事件的默认行为,如 点击 a 标签时禁止跳转
  • stopPropagation:终止事件在传播过程的捕获或冒泡阶段进一步传播

事件代理

在前面简单介绍过:e.target 是指触发事件的具体元素,就算事件处理函数没有绑定在目标元素上、而是绑定在了目标元素的父元素上,由于冒泡机制的存在,目标元素仍然是冒泡到父容器上触发的,仍然可以通过父元素的 target 来感知到目标子元素

利用事件的冒泡特性,把多个子元素的同一类型的监听逻辑,合并到父元素上通过一个监听函数来管理的行为,就是事件代理

如下所示,假设我想每点击一个元素就打印该元素的文本内容,给全部的 li 标签都注册同一个事件当然可以,但是这种做法不仅代码逻辑冗余,而且浪费开销。

在这里插入图片描述


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    #li-wrap{
      background-color: azure;
    }
  </style>
</head>
<body>
  <ul id="li-wrap">
    <li>这是第一行</li>
    <li>这是第二行</li>
    <li>这是第三行</li>
    <li>这是第四行</li>
    <li>这是第五行</li>
    <li>这是第六行</li>
    <li>这是第七行</li>
  </ul>

  <script>
  </script>
</body>
</html>

点击任何一个 li 标签时,该点击事件都会被冒到它们共同父元素上,id为 li-wrap 的父元素不仅能感知到子元素的事件,还可以通过 e.target 拿到实际触发事件的具体子元素,实现事件代理。因此我们可以这么做:

  <script>
    const parent = document.getElementById('li-wrap')
    parent.addEventListener('click', function(e) {
    	console.log(e.target.innerHTML, e)
	}) 
  </script>

这样就实现了事件代理👇
在这里插入图片描述

总结

事件流

  • 事件与事件监听

  • 事件捕获、事件冒泡

事件对象

  • 事件对象的属性

  • 事件对象的方法

事件代理

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值