DOM事件及事件委托解析

392 阅读4分钟

DOM事件及事件委托

DOM事件

概念

事件是什么?有人说是“click”,有人说是“addEeventlistener()”,也有人说把它当成浏览器特有的一种属性。

以上说法都沾了边,但是却都不准确。

简单来说,DOM事件其实就是代码文档与浏览器发生的一些交互的瞬间瞬间这个词,划重点!

4.jpg

语法
element.addElementListener('事件',fn)

常用的就是这样咯,为元素添加事件类型,并为其续上想执行的函数。

W3C会在后边加上bool:

​ bool为true时,在捕获阶段监听

​ bool不传或者为false时,在冒泡阶段监听

什么时冒泡?什么是捕获?接下来我将为你介绍他们!


事件捕获与事件冒泡

事件流

在说捕获和冒泡之前,我们得了解一下事件流是什么样的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件模型</title>
</head>
<body>
    <div class="张三丰">
        <div class="张翠山">
              <div class="张无忌">
                  一起练太极
              </div>
        </div>
    <div>
</body>
</html>

以上是一个多层结构的html代码块,当我们为这三个div都套上**'click'**点击事件。

当我点击“一起练太极”时,他们仨的fn都被调用了吗?

答案:是的,点击文字,等于把他们三个都点了

他们的调用顺序呢?

答案:可以是 张三丰 -> 张翠山 -> 张无忌 ;也可以是 张无忌 -> 张翠山-> 张三丰

这个调用的过程,其实就是页面接收事件的顺序,也叫事件流。


事件捕获与事件冒泡

当调用顺序为:张三丰 -> 张翠山 -> 张无忌 时,事件调用的顺序是由父元素向子元素的,这便是事件捕获

当调用顺序为: 张无忌 -> 张翠山-> 张三丰 时,事件调用顺序是由子元素向父元素的,这便是事件冒泡

默认的调用顺序是:张三丰 -> 张翠山 -> 张无忌 这种事件捕获,当然我们可以选择冒泡顺序

如果你感觉理解困难,那么可以看一下这张图:

6.png

在这里,我们可以总结一下:

一个事件分为三个阶段:

  • 捕获阶段

    即从 张三丰 -> 张翠山 -> 张无忌 这个从外部元素向内部元素寻找监听函数的过程

  • 目标阶段

    即 触发底层元素监听函数,如果有函数,就调用,没有就跳过

  • 冒泡阶段

    即从 张无忌 -> 张翠山-> 张三丰 这个从内部元素向外部元素寻找监听函数的过程

一个特殊的例子

有这么一个div,其捕获阶段、冒泡阶段的事件相同。于是我们将它的两个阶段的代码写到一起:

div.addEventListener('click'.f1) //冒泡
div.addEventListener('click'.f2true) //捕获

以上代码,f1和f2谁先执行呢?

答案:f1先执行

同一级的事件执行顺序,谁先监听就先执行谁,如果f2放在前面,就先执行f2

事件委托

概念

假设你是李云龙,现在你想训练50个炮兵,但你只有1门意大利炮。

8.jpg

你可以选择指定一名班长来帮你协调训练。当然也可以选择突击小鬼子,弄他个50门意大利炮一人一台。

7.jpg 如果你选择后者,不能说你做错了,只能佩服你的勇气。不过大多数情况下我还是比较喜欢委托班长。

这个例子跟事件委托很相像,当你的代码是这样的时候:

<div = '班长'>
 <button>炮兵1号</button>
  <button>炮兵2号</button>
   <button>炮兵3号</button>
    <button>炮兵4号/button>
     <button>炮兵5号</button>
     ...
      <button炮兵49号</button>
       <button>炮兵50号</button>
</div>

假如你给每个炮兵都配上一个大炮(函数),那么对内存的消耗就特别大了。但是你将事件绑定在父级元素,也就是委托到div身上,在执行事件的时候再去匹配判断目标元素,那么就轻松多了。

例子

假设我们有这样一个html代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>云龙意大利炮培养计划</title>
</head>
<body>
  <div id="admiral">
    <button>solider 1</button>
    <button>solider 2</button>
    <button>solider 3</button>
    <button>solider 4</button>
    <button>solider 5</button>
    <button>solider 6</button>
    <button>solider 7</button>
    ...
    <button>solider 49</button>
    <button>solider 50</button>
  </div>
</body>
</html>

如果你为每一个button都设置一个监听事件,那么对内存的消耗就实在太大了(想想李云龙得杀多少鬼子才可以为每一名炮兵配置一台意大利炮)。

好在我们可以将监听事件放在div这个父元素身上,让它去甄别用户操作的元素什么时候会被监听。这就好比你可以配一个非常懂训练班长给这50名炮兵,让他去监管安排训练事宜,他想训练哪一名就训练哪一名。

话不多说,让我们开始吧!

首先我们将监听事件绑定到div身上(相当于给炮兵们配个班长。)

admiral.addEventListener('click',(e)=>{})//将事件绑定到父元素#admiral之上

接着,我们需要赋予该父元素对这些子元素监听的权利。

admiral.addEventListener('click',(e)=>{
    const t = e.target  
    if(t.tagName.toLowerCase() === 'button'){
  console.log(t.textContent+' 被点名训练')
  //如果点击的标签是button,那么函数就生效
}                     
})//将事件绑定到父元素admiral之上

如此你点击哪一个button,哪一个就会做出相应了。

9.jpg

事件委托就是这样简单而又实用。

如果你还不懂也没关系,自己动手多敲几遍就能理顺了。