Hello,最近又准备面试了,通过前几次面试经历,有很深刻的感受,一定要注重基础,注重基础,注重基础!
不要觉得自己用了一些轮子写了一些看起来很不错的项目和功能,就一定能找到好工作。那些轮子不是你写的,你只是一个搬运工…
我们要养成一个好的习惯,不要觉得我用这个轮子写了这个功能,这个功能就是我实现的,我就很厉害,厉害的是轮子,和你没关系,你做的事情,几乎所有人都能做。
最近复习到了原生JS的部分,这期给大家带来事件冒泡和事件代理。这部分的内容面试也经常遇到,在大厂面试中出现的频率也很频繁。
事件冒泡的来龙去脉
啥是事件冒泡呢,我们以一个简单的例子了解一下。
<!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>
<style>
.father {
width: 200px;
height: 200px;
border: 1px solid #000;
}
.child {
width: 100px;
height: 100px;
}
.child.child-1 {
background-color: red;
}
.child.child-2 {
background-color: orange ;
}
</style>
</head>
<body>
<div class="father">
<div class="child child-1"></div>
<div class="child child-2"></div>
</div>
<script>
var oFather = document.getElementsByClassName('father')[0],
oChild1 = document.getElementsByClassName('child-1')[0],
oChild2 = document.getElementsByClassName('child-2')[0];
oFather.onclick = function() {
console.log('father');
}
oChild1.onclick = function() {
console.log('child-1');
}
oChild2.onclick = function() {
console.log('child-2');
}
</script>
</body>
</html>
上面的代码,我写了一个div
为father
,内容有两个同级div
,分别为child-1
和child-2
。
并且我分别给它们添加了样式。
在浏览器中,它的渲染结果如下:
然后我写了一些JS代码,通过DOM
操作,分别拿到三个div
的节点,然后分别绑定各自点击事件的处理函数。
那么我现在点击一下网页中的红色区域,应该输出什么呢?
正常的思路应该觉得肯定输入child-1
呀,因为红色的区域代表div
的class
属性为child child-1
的部分。
那么我们看一下实际的效果。
控制台先输出了child-1
,然后输出了father
。
这是什么原因呢?
肯定有同学会说,因为child-1
在father
的内部,你点击了child-1
也相当于点击了father
。
ok,思路很清晰,那么我稍微改一下CSS代码。
现在child-1
和child-2
在视图上脱离了father
容器,我继续点击红色区域会输出什么?
还是相同的结果。
又有同学要说了,虽然你在视图上让child-1
和child-2
脱离了father
,但是在实际的HTML结构中,child-1
和child-2
仍然属于father
的子标签。
ok,没有问题,这种思路完全没有问题,但是这样的思路不利于我们学习事件冒泡的原理。
我们换一个思路思考一下。
我在body
上添加一个点击事件的处理函数,并且进行输出呢。我们再次点击child-1
的时候,会不会触发body
标签的输出?
没错,body
的点击事件也会被触发。
我们按照这个思路,继续向上寻找,给html
标签也绑定,给document
也绑定,最后给window
也绑定上点击事件的处理函数。
果然,这个点击事件的处理函数,被逐级触发~~~~
是不是很奇妙,虽然按照之前的思路,也可以解释的过去,但是还是希望大家以事件冒泡的思路去理解这个问题。
其实在很多的业务开发中,都会碰到类似的问题,我只是想让它自己的点击事件触发,但是它父类的点击事件也会跟着不小心触发,这就是烦恼。
那么我们介绍完事件冒泡的来龙去脉之后,我们要如何避免它呢?
避免事件冒泡的产生
我们在oChild1
的点击事件处理函数中,添加一个参数e
,并且在函数内部,输出这个e
。然后看下控制台。
有一个MouseEvent
的对象被打印出来。
我们试着跟踪一下它的原型链。
我们可以看到,跟着它的原型链走,分别经历了MouseEvent -> mouseEvent -> UIEvent -> Event -> Object
。
我们着重看一下,在Event
对象中,有一个stopPropagation
方法,这个就是停止事件冒泡的方法,然后cancelBubble
属性,默认是false
这两个都可以停止事件冒泡。
它们的区别主要是stopPropagation()
是符合W3C
标准的,也就是说,大部分的浏览器都可以使用,cancelBubble
是IE
浏览器中处理事件冒泡的属性。
所以,在处理浏览器兼容的时候,它们才会有区别,功能是一摸一样的。
oChild1.onclick = function(e) {
console.log(e);
var e = e || window.event;
if (e.stopPropagation) {
e.stopPropagation();
}else {
e.cancelBubble = true;
}
console.log('child-1');
}
这样写,就是最标准的,考虑兼容的,处理事件冒泡的方法。
经过我们的处理,现在再次点击红色区域的时候,它只会输出点击事件处理函数中的输出语句,不会向上冒泡。
ok,以上就是关于事件冒泡的来龙去脉以及处理方法。
因为文章篇幅有限,关于事件代理的内容,下期再介绍~~~
顺便说一下,最近在找实习,有合适工作的可以给我内推一下~~,前端岗,最好base北京
联系方式
QQ:505417246
微信:18331092918