细说事件流

      相信大家对事件流有一点的认识,在这里我就通过一个例子来说明其中的细节。这是你知道的不知道的,不知道的知道的,笑死。

一、事件阶段:

      捕获阶段 目标阶段 冒泡阶段

二、案例分析

1.html部分

<div id='wrapDiv'>wrapDiv
     <p id="innerP">innerP
         <span id="textSpan">textSpan</span>
     </p>
</div>

2.css部分

 <style>
        #wrapDiv,
        #innerP,
        #textSpan {
            box-sizing: border-box;
            /**width+padding+border**/
            margin: 40px;
            cursor: pointer;
        }

        #wrapDiv {
            width: 300px;
            height: 300px;
            border: crimson solid 3px;
        }

        #innerP {
            width: 200px;
            height: 200px;
            border: green solid 3px;
        }

        #textSpan {
            width: 100px;
            height: 100px;
            border: blue solid 3px;
            display: block;
        } 
</style>

3.js部分

        var wrapDiv=document.getElementById('wrapDiv');
        var innerP=document.getElementById('innerP');
        var textSpan=document.getElementById('textSpan');
        // Event.currentTarget指向事件绑定的元素,而 Event.target 则是事件触发的元素。


        // true 表示捕获阶段
        window.addEventListener('click',function(e){
            console.log('window捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        document.addEventListener('click',function(e){
            console.log('document捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        document.documentElement.addEventListener('click',function(e){
            console.log('documentElement捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        document.body.addEventListener('click',function(e){
            console.log('body捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        wrapDiv.addEventListener('click',function(e){
            console.log('wrapDiv捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        innerP.addEventListener('click',function(e){
            console.log('innerP捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        textSpan.addEventListener('click',function(e){
            console.log('textSpan捕获',e.target.nodeName,e.currentTarget.nodeName);
        },true);
        
        // false 表示冒泡阶段
        window.addEventListener('click',function(e){
            console.log('window冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        document.addEventListener('click',function(e){
            console.log('document冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        document.documentElement.addEventListener('click',function(e){
            console.log('documentElement冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        document.body.addEventListener('click',function(e){
            console.log('body冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        wrapDiv.addEventListener('click',function(e){
            console.log('wrapDiv冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        innerP.addEventListener('click',function(e){
            console.log('innerP冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);
        textSpan.addEventListener('click',function(e){
            console.log('textSpan冒泡',e.target.nodeName,e.currentTarget.nodeName);
        },false);

4.页面效果

问题来了来了!!!

(1).当点击span结果会是什么?(先捕获后冒泡 顺序看打印结果)

 

(2).如果将目标元素的冒泡和捕获绑定顺序互换 (打印结果出了目标元素的冒泡和捕获是根据绑定的顺序有关(谁先绑定谁先触发),所以在目标阶段 不一定是先捕获后冒泡

        // true 表示捕获阶段
        window.addEventListener('click', function (e) {
            //window无nodeName所以打印出来是undefined,不要见怪哦。
            console.log('window捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.addEventListener('click', function (e) {
            console.log('document捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.body.addEventListener('click', function (e) {
            console.log('body捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        innerP.addEventListener('click', function (e) {
            console.log('innerP捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);

        // 将被点击元素提前
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);

        // false 表示冒泡阶段
        window.addEventListener('click', function (e) {
            console.log('window冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.addEventListener('click', function (e) {
            console.log('document冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.body.addEventListener('click', function (e) {
            console.log('body冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        innerP.addEventListener('click', function (e) {
            console.log('innerP冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);

(3).如果给元素绑定onclick呢,和addEventLister又有什么区别呢?

A:onclick这样的事件,给同一个元素,同一个事件绑定多个处理函数后面会覆盖前面的

B:addEventLister 就可以实现同一个元素,同一个事件对应多个处理函数,不会覆盖

C:onclick和addEventLister混合使用,不会影响

D.onclick可以统一看做是在冒泡阶段,为什么这么说看下面例子

    <script>
        var wrapDiv = document.getElementById('wrapDiv');
        var innerP = document.getElementById('innerP');
        var textSpan = document.getElementById('textSpan');
        // Event.currentTarget指向事件绑定的元素,而 Event.target 则是事件触发的元素。
       
        // 添加onclick事件
        wrapDiv.onclick = function (e) {
            console.log('使用wrapDiv.onclick,直接绑定的元素,但不是直接触发的元素:在冒泡阶段触发', e.target.nodeName, e.currentTarget.nodeName);
        }
        textSpan.onclick = function (e) {
            console.log('使用textSpan.onclick,既是直接绑定的元素,又是直接触发的元素:发生在哪个阶段是根据它和绑定捕获的位置有关,谁在前谁先触发', e.target.nodeName, e.currentTarget.nodeName);
        }

        // true 表示捕获阶段
        window.addEventListener('click', function (e) {
            console.log('window捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.addEventListener('click', function (e) {
            console.log('document捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.body.addEventListener('click', function (e) {
            console.log('body捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        innerP.addEventListener('click', function (e) {
            console.log('innerP捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);


        // false 表示冒泡阶段
        window.addEventListener('click', function (e) {
            console.log('window冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.addEventListener('click', function (e) {
            console.log('document冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.body.addEventListener('click', function (e) {
            console.log('body冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        innerP.addEventListener('click', function (e) {
            console.log('innerP冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);    
    </script>

(4).阻止事件传播(e.stopPropagation();阻止冒泡,其实也可以阻止捕获

        // true 表示捕获阶段
        window.addEventListener('click', function (e) {
            console.log('window捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.addEventListener('click', function (e) {
            console.log('document捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        document.body.addEventListener('click', function (e) {
            console.log('body捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv捕获', e.target.nodeName, e.currentTarget.nodeName);
            //在捕获阶段阻止事件的传播
            e.stopPropagation();
            // 或使用
            // e.cancelBubble = true;  //这个属性的规范并未统一 少用,知道就行

        }, true);
        innerP.addEventListener('click', function (e) {
            console.log('innerP捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan捕获', e.target.nodeName, e.currentTarget.nodeName);
        }, true);


        // false 表示冒泡阶段
        window.addEventListener('click', function (e) {
            console.log('window冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.addEventListener('click', function (e) {
            console.log('document冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.documentElement.addEventListener('click', function (e) {
            console.log('documentElement冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        document.body.addEventListener('click', function (e) {
            console.log('body冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        wrapDiv.addEventListener('click', function (e) {
            console.log('wrapDiv冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        innerP.addEventListener('click', function (e) {
            console.log('innerP冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false);
        textSpan.addEventListener('click', function (e) {
            console.log('textSpan冒泡', e.target.nodeName, e.currentTarget.nodeName);
        }, false); 

 

(5).拓展:js中preventDefault()阻止事件的默认行为,而不是在阻止冒泡

// 默认行为是指:点击a标签就跳转,拖拽一个图片到浏览器会自动打开,点击表单的提交按钮会提交表单
     e.preventDefault();
     //或
    //return false;

(6).addEventListener兼容问题(使用attachEvent)

if (el.addEventListener) {
  el.addEventListener('click', modifyText, false); 
} else if (el.attachEvent)  { //兼容IE9之前
  el.attachEvent('onclick', modifyText);//无第三个参数
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值