DOM事件及事件委托
DOM事件
概念
事件是什么?有人说是“click”,有人说是“addEeventlistener()”,也有人说把它当成浏览器特有的一种属性。
以上说法都沾了边,但是却都不准确。
简单来说,DOM事件其实就是代码文档与浏览器发生的一些交互的瞬间。瞬间这个词,划重点!
语法
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都被调用了吗?
答案:是的,点击文字,等于把他们三个都点了
他们的调用顺序呢?
答案:可以是 张三丰 -> 张翠山 -> 张无忌 ;也可以是 张无忌 -> 张翠山-> 张三丰
这个调用的过程,其实就是页面接收事件的顺序,也叫事件流。
事件捕获与事件冒泡
当调用顺序为:张三丰 -> 张翠山 -> 张无忌 时,事件调用的顺序是由父元素向子元素的,这便是事件捕获
当调用顺序为: 张无忌 -> 张翠山-> 张三丰 时,事件调用顺序是由子元素向父元素的,这便是事件冒泡
默认的调用顺序是:张三丰 -> 张翠山 -> 张无忌 这种事件捕获,当然我们可以选择冒泡顺序
如果你感觉理解困难,那么可以看一下这张图:
在这里,我们可以总结一下:
一个事件分为三个阶段:
-
捕获阶段
即从 张三丰 -> 张翠山 -> 张无忌 这个从外部元素向内部元素寻找监听函数的过程
-
目标阶段
即 触发底层元素监听函数,如果有函数,就调用,没有就跳过
-
冒泡阶段
即从 张无忌 -> 张翠山-> 张三丰 这个从内部元素向外部元素寻找监听函数的过程
一个特殊的例子
有这么一个div,其捕获阶段、冒泡阶段的事件相同。于是我们将它的两个阶段的代码写到一起:
div.addEventListener('click'.f1) //冒泡
div.addEventListener('click'.f2,true) //捕获
以上代码,f1和f2谁先执行呢?
答案:f1先执行
同一级的事件执行顺序,谁先监听就先执行谁,如果f2放在前面,就先执行f2
事件委托
概念
假设你是李云龙,现在你想训练50个炮兵,但你只有1门意大利炮。
你可以选择指定一名班长来帮你协调训练。当然也可以选择突击小鬼子,弄他个50门意大利炮一人一台。
如果你选择后者,不能说你做错了,只能佩服你的勇气。不过大多数情况下我还是比较喜欢委托班长。
这个例子跟事件委托很相像,当你的代码是这样的时候:
<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,哪一个就会做出相应了。
事件委托就是这样简单而又实用。
如果你还不懂也没关系,自己动手多敲几遍就能理顺了。