天天看点

关于事件冒泡和事件代理,看这一篇就够了!(上篇)

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,以上就是关于事件冒泡的来龙去脉以及处理方法。

上一篇: Nginx基础