zoukankan      html  css  js  c++  java
  • 事件冒泡与事件捕获

    引言:用户在浏览器操作的时候触发的一种行为就叫事件。

    每个元素自身都有事件,只不过默认为null(没有事件,事件值就为undefined),当某个事件绑定一个函数之后,用户在操作浏览器的时候触发了这个事件,就会执行这个事件函数。

    什么是事件冒泡和捕获呢?

    来看一张图(简单明了~)

    由上图我们可以得知

    事件冒泡就是从目标元素自下而上一直到window(结束)这样一个过程

    事件捕获就是从window自上而下一直到目标元素的这样一个过程

    一般是先执行捕获,后执行冒泡

    关于冒泡:

    ① DOM0,DOM2都有冒泡行为

    ② 目标元素和祖先元素绑定同一事件时候,目标元素触发的同时祖先元素也会执行这一事件

    来,看个小栗子

       DOM0 事件冒泡 
      window.onclick = function(){ alert('window'); } box1.onclick = function(){ alert('第一个'); }; box2.onclick = function(){ alert('第二个'); }; box3.onclick = function(){ alert('第三个'); }; //点击 box3分别会由下而上 弹第三个,第二个,第一个,window
    DOM2 事件冒泡
        div1.addEventListener('click',function(){
            alert('red');
        },false);
        div2.addEventListener('click',function(){
            alert('green');
        },false);
        btn.addEventListener('click',function(){
            alert('按钮');
        },false);
         //依次输出 按钮 -> green -> red

    以上分别是DOM0和DOM2中的冒泡

    冒泡的优点可以通过事件对象的target捕获到事件源是哪个元素,从而提高性能

    但在开发中也会遇到冒泡带来的弊端(由于冒泡机制,子元素触发事件时候也会影响父元素和祖先元素)

    比如以下效果:

        let onOff = true;
        btn.onclick = function(ev){
            if(onOff){
                box.style.display = 'none';
            }else{
                box.style.display = 'block';
            }
            onOff = !onOff;
        }
        document.onclick = function(){
            box.style.display = 'none';
            onOff = false;
        }

    问题:点击按钮隐藏红色背景,再次点击按钮时候红色背景应该显示。但因为冒泡的特性,执行完按钮的onclick事件函数,还会执行document,所以再次点击按钮是没有反映的

     解决方法:使用stopPropagation() 和 cancelBubble阻止冒泡的发生

        let onOff = true;
        btn.onclick = function(ev){
            if(onOff){
                box.style.display = 'none';
            }else{
                box.style.display = 'block';
            }
            onOff = !onOff;
            // ev.stopPropagation();
            ev.cancelBubble = true; //阻止了btn的onclick的事件不往上面冒泡。
        }
    
        document.onclick = function(){
            box.style.display = 'none';
            onOff = false;
        }

    其中ev.stopPropagation是W3C标准写法,IE低版本不支持

      ev.cancelBubble = true;这个方法虽然不是标准方法,但大多数浏览器都支持...

    注意:开发中如果两个元素是嵌套关系就要小心时间冒泡了,名称尽量不要重复

    关于捕获:

    ① DOM0是检测不到捕获的,只有DOM2/3才能捕获到

    ② addEventListener/removeEventListener中的布尔值默认都是false不捕获

      div1.addEventListener('click',function(){
            alert('red');
        },true);
        div2.addEventListener('click',function(){
            alert('green');
        },true);
        btn.addEventListener('click',function(){
            alert('按钮');
        },true);
        //点击btn依次输出 red -> green -> 按钮

    事件流(模型)

    当一个事件触发时,一般会经历三个过程。即捕获阶段(window由上而下到目标元素)、目标阶段冒泡阶段(目标元素由下而上到window),这么个过程称为事件流(事件模型)

    其中目标阶段,他是按照事件绑定的先后顺序,而不是按照先捕获后冒泡这一规则来执行

    下面是事件流的一些小测试

           div1.addEventListener('click',function(){
                console.log('red');
            },true);
            div2.addEventListener('click',function(){
                console.log('green');
            },false);
            btn.addEventListener('click',function(){
                console.log('按钮');
            },false);  
            function fn(){  console.log('tred');}
            btn.addEventListener('click',function(){
                console.log('按钮2');
            },false);
            div2.addEventListener('click',function(){
                console.log('tgreen');
            },true);
            div1.addEventListener('click',fn,true);
            div1.addEventListener('click',function(){
                console.log('red');
            },false);
            btn.addEventListener('click',function(){
                console.log('t按钮');
            },true);
            div2.addEventListener('click',function(){
                console.log('green');
            },false);
            btn.addEventListener('click',function(){
                console.log('按钮');
            },false);
    //点击btn依次会输出下面结果 //red->tred->tgreen->按钮->按钮2->t按钮->按钮->green->green->red

    PS:下面说下DOM0和DOM2 (木有DOM1...)

    DOM0就是传统的事件,比如以on开头。DOM0检测不到事件捕获行为

    DOM2有两个方法来处理事件:绑定 -> addEventListener()、解绑 -> removeEventListener()

    绑定事件方法:

    /*
    第一个参数:不带on的事件名称
    第二个参数:事件函数
    第三个参数:布尔值,是否捕获。默认false不捕获
    */
    ele.addEventListener("不带on的事件名","事件函数","是否捕获")

    解绑事件方法:

    /*
    第一个参数:不带on的事件名称
    第二个参数:解绑的事件函数
    第三个参数:布尔值,是否捕获。默认false不捕获
    */
    ele.removeEventListener("不带on的事件名","解绑事件函数","是否捕获")

    除了上面的两种方法,还有IE下面的两个绑定、解绑方法

    attachEvent('带on事件名',‘事件函数’)
    detachEvent('带on事件名',‘事件函数’)

    注意:这里的第一个参数是带on的事件名

  • 相关阅读:
    JVM 参数(转)
    redis 事务
    redis 命令
    Redis配置文件参数说明(转)
    zookeeper原理(转)
    数字证书原理 转载
    证书 签名 验签 实例
    SSL双向认证java实现 (转)
    详细介绍Java垃圾回收机制 转载
    Java Socket重要参数讲解 (转载)
  • 原文地址:https://www.cnblogs.com/theblogs/p/9972904.html
Copyright © 2011-2022 走看看