持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
我们知道对于js的事件来说存在三个个阶段,一是事件捕获阶段,二是目标阶段,三是事件冒泡阶段,当标签又多层结构的时候,事件触发的时候,事件由外层向内层传递我们称之为事件捕获阶段,事件由内向外传递的过程我们称之为事件冒泡;原生js我们使用stopPropagation来阻止事件冒泡,vue中可以用事件修饰符stop来阻止事件冒泡,对于事件冒泡我们有个很经常的用途就是用来进行事件委托处理。
什么是事件委托
如ul>(li*100)这个时候要给每一个li添加点击事件,我们只需要给ul添加点击事件,当点击li的时候通过事件冒泡,就可以触发事件了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>
如上面这种文档结构,如果我们要给li添加点击事件,那么我们就要一个个的进行循环添加
let liArr = document.getElementsByTagName('li');
liArr.forEach(element => {
element.onclick=function(){
dosomething();
。。。。
}
});
这样肯定是能实现我们的需求的,但是带来的问题就是每一个li上都绑定了一个事件,十分消耗性能,同时如果我的li是动态改变的,那么新增的li我又要重新进行绑定。
事件委托进行实现
事件冒泡就是事件在本元素触发后,会像泡泡一样一层一层的向外扩展,那么在事件触发元素的父元素也是可以监听到的,所以我们可以在父元素那里统一进行监听后处理:
let ulArr = document.getElementsByTagName('ul');
ulArr[0].onclick=function(e){
if(e.target.tagName.toLowerCase()=='li'){
doSomething();
。。。
}
}
这样当li的点击事件触发的时候,就会通过事件冒泡的形式被ul的监听到,然后触发响应的回调函数进行处理,可以看到这样我们原本每一个li都要进行绑定事件的,现在只有其公共父元素ul需要绑定,大大的优化了性能,同时如果后续li再动态增加也没有关系,因为其层级关系并没有改变。
优化
但是这样写还是有一些问题存在,假设我的li并不是单纯的li,里面还包含有其他的元素,那么其他元素所触发的点击事件就不会触发父元素的回调函数了,因为此时触发事件的元素已经不是我们的li元素了。
解决方法其实也不难,也就是我们在判断触发元素的时候,还要判断一下触发事件元素的父元素中是否存在li元素,如果存在那么就说明,其实li中的内部元素,其触发的事件应该也是要归属于我们的li的,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>1</li>
<li>
<span>测试</span>
</li>
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
</body>
</html>
<script>
let ulArr = document.getElementsByTagName('ul');
ulArr[0].onclick=function(e){
let even=e.target;
while(!even.tagName.toLowerCase()=='li'){
if(ulArr[0]===even){
even=null;
break;
}
even=even.parentNode;
}
even&&console.log("doSomeThing...");
}
</script>