事件冒泡与事件捕获

事件流

JS事件流最早要从IE和网景的浏览器大战说起,IE提出冒泡流,网景提出捕获流。后来在W3C统一下,js支持了捕获流和冒泡流,但是低版本的如IE6,IE7,IE8只支持冒泡流,所以为了浏览器兼容,还是建议使用冒泡流。

JS事件流的主要过程

首先来看一段代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <style>
        .box{
            width:500px;
            height:500px;
            border:1px solid #ff0;
        }
        .box01,.box02{
            width:100px;
            height:100px;
            margin:100px 0 0 200px;
        }
        .box01{
            border:1px solid #f0f;
        }
        .box02{
            border:1px solid #0ff;
        }
    </style>
</head>
<body>
    <div class="box">
        <div class="box01"></div>
        <div class="box02"></div>
    </div>
</body>
<script>
$('.box').click(function(){
    console.log("box")
})
$('.box01').click(function(){
    console.log("box01")
})
$('.box02').click(function(){
    console.log("box02")
})
</script>
</html>

将代码运行一下,点击类名为box01或box02的div,查看控制台即可得出子元素div的点击先触发,父级元素div的点击事件再触发。这个跟事件触发顺序有关。
事件冒泡与事件捕获(图片转载侵删)
由上图可知,
1.一个完整的JS事件流是从window开始,最后回到window的一个过程。
2.事件流被分为三个阶段(1-5)捕获过程、(5-6)目标过程、(6-10)冒泡过程。
3.在冒泡过程中6比7早触发,也就解释了上面那题,为什么box01和box02,会比box先触发。

关于事件冒泡和事件捕获

事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件。相反的,事件冒泡是自下而上的去触发事件。绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获。true,事件捕获;false,事件冒泡。默认false,即事件冒泡。Jquery的e.stopPropagation会阻止冒泡。

举个例子

先举一个例子,上html结构

<div id="outer">
  <div id=inner" class="inner"></div>
</div>

接着给它们绑上事件

document.getElementById("outer").addEventListener("click",function(e){
    alert("outer事件被触发,"+this.id);
})
document.getElementById("inner").addEventListener("click",function(e){
    alert("inner事件被触发,"+this.id)
})

结果
inner事件被触发,inner
outer事件被触发,outer

结论:先inner,然后outer。事件的触发顺序自内向外,这就是事件冒泡.

改变一下参数

现在我们给它改变一下参数

document.getElementById("outer").addEventListener("click",function(e){
    alert("outer事件被触发,"+e.target.id);
 },true)
document.getElementById("inner").addEventListener("click",function(e){
    alert("child事件被触发,"+e.target.id)
},true)

结果

outer事件被触发,outer
inner事件被触发,inner

结论:先outer,然后inner。事件的触发顺序自外向内,这就是事件捕获.

举个实例

貌似还是说的不太清,现在举个实例

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

我们的需求是,鼠标移到li身上,对应li变色
我们可以给每个li绑上事件,比如…

$("li").on("mouseover",function(){
    $(this).css("background-color","#cecece").siblings().css("background-color","white");
})

也可以利用事件冒泡来实现

$("ul").on("mouseover",function(e){
   $(e.target).css("background-color","#cecece").siblings().css("background-color","white");
})

从简洁的程度上,两者差不多,但是事件冒泡明显比前面少了个遍历的过程,代码明显更优,而且如果ul再添加li子节点的话,新增的li一样会有点击事件的,这样下来,用事件冒泡来写的话更是方便了不少,这就涉及到了事件委托。