js事件流及事件委托详解

 

 一.事件流

在讲事件流之前,我们先来了解一下什么是事件流,为什么要使用事件流。首先我们来看一个场景:

一个Div嵌套了一个Button按钮,当2个元素都注册了click点击事件。点击里面的Button按钮时,Div的click事件也会触发。

那么问题来了,既然都会触发,得有个触发的顺序吧?是按照Div → Button这样的顺序触发,还是按照Button → Div的顺序触发?

这个时候我们就用到了事件流。

事件流分为两种,事件冒泡和事件捕获:

捕获阶段(Capture Phase):事件从最外层的window对象到目标节点的父节点依次触发的阶段。(从外到内)

冒泡阶段(Bubbing Phase):事件从目标节点的父节点到最外层的window对象依次触发的阶段。(从内到外)

在DOM0级事件中,我们一般使用如下方法绑定点击事件:

在DOM0级事件中,事件流为事件冒泡。即事件从开始时最具体的元素接收,然后逐级向上传播到较为不具体的节点。也就是上面代码中four的点击事件触发顺序为four=>three=>two=>one。

DOM2事件规范制定了事件流的三个阶段:捕获阶段目标阶段冒泡阶段。

捕获阶段(Capture Phase):事件从最外层的window对象到目标节点的父节点依次触发的阶段。(从外到内)

目标阶段(Target Phase):事件在目标节点上触发时的阶段。

冒泡阶段(Bubbing Phase):事件从目标节点的父节点到最外层的window对象依次触发的阶段。(从内到外)

在DOM2中,元素对象通过addEventListener()注册事件,此方法的第三个参数可设置本次注册是捕获阶段还是冒泡阶段。也就是说我们在注册事件时,可以设置事件的触发顺序。

addEventListener()方法说明

语法:EventTarget.addEventListener(eventName, eventHandler ,[ useCapture] )

参数

①eventName {string} :所要注册的事件名称,不区分大小写。此名称不需要像注册事件属性那样在前缀加上"on"。如注册鼠标点击事件,写为click。

②eventHandler {function | function Object} :函数或者函数对象。事件触发时所需要执行的函数;当使用函数对象多次注册同一事件时,只当注册一遍。

③useCapture {boolean} 可选 :是否处于捕获阶段,默认为false。

  true:当前注册的事件为捕获阶段。

  false:当前注册的事件不为捕获阶段,为冒泡阶段。

来看下面这个例子:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        .one{
            height: 400px;
            width: 400px;
            background-color: red
        }
                .two{
            height: 300px;
            width: 300px;
            background-color: blue
        }
                .three{
            height: 200px;
            width: 200px;
            background-color: yellow
        }
                .four{
            height: 100px;
            width: 100px;
            background-color: green
        }
    </style>
</head>
<body>
<div class="one">one
    <div class="two">two
        <div class="three">three
            <div class="four">four</div>
        </div>
    </div>
</div>

</body>
<script type="text/javascript">
    var a=document.querySelector('.one');
    a.addEventListener("click",function(){
        alert("one")
    },false)
    
    var b=document.querySelector('.two');
    b.addEventListener("click",function(){
        alert("two")
    },true)
    var c=document.querySelector('.three');
    c.addEventListener("click",function(){
        alert("three")
    },false)
    var d=document.querySelector('.four');
    d.addEventListener("click",function(){
        alert("four")
    },true)
</script>
</html>

这个例子中,点击four之后事件的触发顺序是怎么样的呢?顺序应该是two=>four=>three=>one。顺序为什么是这样的呢?我们来分析一下代码,one和three添加的点击事件为最后一个参数为false,two和four添加的点击事件为最后一个参数为true,也就是说one和three的事件流为事件冒泡,two和four的事件流为事件捕获。在上面的图中我们知道,先进行事件捕获后进行事件冒泡。所以two的点击事件最先触发,然后是four,再然后进行事件冒泡,触发three和one。

现在我们清楚了事件的顺序,但还有一个问题,有时候我们点击four时,并不想同时触发one,two,three,这时候该怎么办呢?

这时我们就用到了event对象,在这里我们需要使用event对象的stopPropagation方法,这个方法会阻止事件继续传播,关于event对象的具体叙述,大家可以自行百度。在上面的例子中,我们只需将上面代码中添加 event.stopPropagation(),
    d.addEventListener("click",function(){
        alert("four")

event.stopPropagation()
    },true),修改以后当事件流传播到这里时就会停止。因为我们上面设置了两个冒泡,两个捕获,所以修改后显示two和four,想要只触发two,只需将所有事件改为事件冒泡。

二.事件委托

在讲事件委托之前,我们先来了解一下什么是事件委托,为什么要使用事件委托。在前段时间看到了一道面试题,如下:

在一个页面中有一个ul标签,ul标签中有1000个li标签,现在要给每个li标签加一个点击事件,要求考虑页面性能。

我们应该怎么做?循环获取这1000个标签,然后给每个标签加上点击事件?很明显,这是不合理的,前端的同学都知道,操作DOM是很耗费时间和资源的,我们该怎么办呢?这时候就用到了事件委托。下面就是我们将上面的例子改为事件委托后的代码:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        .one{
            height: 400px;
            width: 400px;
            background-color: red
        }
                .two{
            height: 300px;
            width: 300px;
            background-color: blue
        }
                .three{
            height: 200px;
            width: 200px;
            background-color: yellow
        }
                .four{
            height: 100px;
            width: 100px;
            background-color: green
        }
    </style>
</head>
<body>
<div class="one">one
    <div class="two">two
        <div class="three">three
            <div class="four">four</div>
        </div>
    </div>
</div>

</body>
<script type="text/javascript">
var a=document.querySelector('.one');
a.addEventListener('click',function(event){
  var x=event.target
      switch(x.className){
        case "two":
        alert("two")
        break;

        case "three":
        alert("three")
        break;

        case "three":
        alert("three")
        break;
  }

})
</script>
</html>

这段代码中我们只进行了一次DOM操作,就给四个div绑定了点击事件,事件委托使用了事件冒泡的原理,简单来说事件委托就是父元素监听子元素的冒泡事件。当我们点击four时事件会冒泡到one,然后我们在one来处理four传过来的事件,通过event.target来得到事件发生的子元素,然后判断元素的类名,分别绑定点击事件。

猜你喜欢

转载自blog.csdn.net/qq_41635167/article/details/82877876