• 粗浅的总结下事件流


    什么是事件流?以及为什么要有事件流?

    简单的说,事件流就是,确认触发条件满足时,事件对应函数的调用顺序。举个例子,鼠标光标在某个按钮上点击了,按钮又绑定了mousedown事件,那么其对应的函数就会调用。而其实,光标落下的位置也在document、window的范围内,或许还可能在其他元素的盒模型内。如果这些元素也都绑定了mousedown事件,那么哪个元素的mousedown事件对应的函数先调用呢?这就需要确认一个发生的顺序问题。

    具体的说,事件流分为三个阶段,即捕获阶段、目标(处理)阶段、冒泡阶段。网上随便找了一张示意图,如下:

    其实这张图以及网上很多说法(比如百度百科DOM事件流)都不是很严谨,漏掉了window对象。事件流应该是从window开始,在window对象结束(如果捕获阶段和冒泡阶段,window都绑定了事件的话)。估计是window对象通常只在冒泡阶段绑定load事件吧,不谈也没什么影响。

    一个演示事件流的例子

    下图中,在鼠标单击金黄色span区域时,控制台对应打印出日志。

    源代码在这里:

     1 <!DOCTYPE html>
     2 <html id="html">
     3     <head>
     4         <meta charset="UTF-8">
     5         <title></title>
     6         <style>
     7             div{
     8                 width: 200px;
     9                 height: 200px;
    10                 font-size: 30px;
    11                 color: #fff;
    12                 background: green;
    13             }
    14             span{
    15                 display: block;
    16                 width: 100px;
    17                 height: 100px;
    18                 background: goldenrod;
    19                 color: #fff;
    20                 font-size: 30px;
    21             }
    22             body{
    23                 border: 1px solid #000;
    24             }
    25         </style>
    26         <script>
    27             
    28             window.onload=function(){
    29                 var div=document.getElementById("div");
    30                 var span=document.getElementById("span");
    31                 var html=document.getElementById("html");
    32                 var body=document.getElementById("body");
    33                 var head=document.getElementById("head");
    34 
    35                 body.addEventListener('click',function(){console.log('body冒泡')},false);
    36                 html.addEventListener('click',function(){console.log('html冒泡')},false);
    37                 window.addEventListener('click',function(){console.log('window冒泡')},false);
    38                 document.addEventListener('click',function(){console.log('document冒泡')},false);
    39                 div.addEventListener('click',function(){console.log('div冒泡')},false); 
    40                 span.addEventListener('click',function(){console.log('span冒泡')},false);
    41                 span.addEventListener('click',function(){console.log('span捕获')},true);
    42                 document.addEventListener('click',function(){console.log('document捕获')},true);
    43                 window.addEventListener('click',function(){console.log('window捕获')},true);
    44                 html.addEventListener('click',function(){console.log('html捕获')},true);
    45                 body.addEventListener('click',function(){console.log('body捕获')},true);
    46                 div.addEventListener('click',function(){console.log('div捕获')},true);
    47             };
    48         </script>
    49     </head>
    50     <body id="body">
    51         <div id="div">div
    52             <span id="span">span</span>
    53         </div>
    54     </body>
    55 </html>
    View Code

    结合图片和代码,可以发现两个问题:

    1、代码中故意将打印带有“冒泡”字样的语句写在了前面,而且也没有按“window捕获->document捕获->html捕获->body捕获->div捕获->span捕获->span冒泡->div冒泡->body冒泡->html冒泡->document冒泡->window冒泡”这样的顺序,但是控制台中打印的日志基本上与事件流的顺序一致。

    2、第二个问题,也就是控制台中打印的日志与事件流的顺序不一致的地方,为什么“span冒泡”在“span捕获”前面呢?因为,触发的是span绑定的事件,那么span绑定的事件就在目标阶段触发。触发顺按照代码中书写顺序来。本例中,即

     span.addEventListener('click',function(){console.log('span冒泡')},false); 

     span.addEventListener('click',function(){console.log('span捕获')},true); 前面。

    注:

    addEventListener绑定事件语法: 对象.addEventListener(事件名称,事件绑定函数,布尔值)

    布尔值取值说明:
    * true 事件是在捕获的阶段发生的
    * false 事件是在冒泡的阶段发生的(缺省值)

    阻止事件流

    说到事件流,一般都要说下阻止事件流。我们知道可以通过两种方法绑定事件,一种是用on,一种是上面提到的addEventListener。针对绑定事件的方式不同,阻止事件流的方法也不同。

    情况1:

    用on给元素绑定事件,所有的浏览器都是一样的,先触发事件源对象,然后再往外层元素冒泡。所以,只需要阻止冒泡就可以了。将event对象身上的cancelBubble的值设为true即可。

    来看一个例子:

    图中,点击box3后,box3、box2身上的事件会发生。然后,停止在box2,也就是不会在向外冒泡了。所以box1身上的事件没有发生。

    关键代码如下:

     1                 box1.onclick=function(ev){
     2                     console.log('box1点击了');
     3                 };
     4                 box2.onclick=function(ev){
     5                     console.log('box2点击了');
     6                     ev.cancelBubble=true;   //这里阻止了冒泡
     7                 };
     8                 box3.onclick=function(ev){
     9                     console.log('box3点击了');
    10                 };

    情况2:

    用addEventListener绑定事件,可指定事件发生在捕获阶段还是在冒泡阶段。在事件函数内调用event身上的stopPropagation()方法,可以阻止事件流继续蔓延。

    看一个具体的例子:

    图中,因为在冒泡阶段box6绑定的事件函数内,阻止了事件流,点击box6,事件流会在冒泡阶段box6绑定的事件发生后停止。如果没有阻止事件流,那么控制台中将会依次打印:捕获阶段box4点击了->捕获阶段box5点击了->捕获阶段box6点击了->冒泡阶段box4点击了->冒泡阶段box5点击了->冒泡阶段box6点击了。

     

    关键代码如下:

     1                 box4.addEventListener('click',function(ev){
     2                     console.log('捕获阶段box4点击了');
     3                 },true);
     4                 box5.addEventListener('click',function(ev){
     5                     console.log('捕获阶段box5点击了');
     6                 },true);
     7                 box6.addEventListener('click',function(ev){
     8                     console.log('捕获阶段box6点击了');
     9                 },true);
    10                 
    11                 box4.addEventListener('click',function(ev){
    12                     console.log('冒泡阶段box4点击了');
    13                 });
    14                 box5.addEventListener('click',function(ev){
    15                     console.log('冒泡阶段box5点击了');
    16                 });                
    17                 box6.addEventListener('click',function(ev){
    18                     console.log('冒泡阶段box6点击了');
    19                     ev.stopPropagation(); //因为在此处阻止了事件流蔓延,单击box6的时候,只打印'冒泡阶段box6点击了'。不会波及到box5和box4。
    20                 });    

    知识共享许可协议
    本作品采用知识共享署名 4.0 国际许可协议进行许可。

  • 相关阅读:
    增删改
    创建数据库
    数据库的列类型
    数据库
    Python os.ttyname() 方法
    Python os.tmpnam() 方法
    Python os.tmpfile() 方法
    Python os.tempnam() 方法
    Python os.tcsetpgrp() 方法
    LR运行负载测试场景-笔记
  • 原文地址:https://www.cnblogs.com/fortunel/p/6434310.html
Copyright © 2020-2023  润新知