js中的事件机制--捕获、触发、冒泡

一、事件绑定的集中方式: 
1.1通过在html标签中加入onclick,onblur等。 
<div id="outestA" onclick="var id = this.id;alert(id);return false;"></div> 
但是这种不做不值得提倡。 
1.2在onclick中指定函数名:

<script>
    function buttonHandler(thisDom)
    {
        alert(this.id);//undefined
        alert(thisDom.id);//outestA
        return false;
    }
</script>
<div id="outestA" onclick="return buttonHandler(this);"></div>

1.3 在js中通过dom元素的onclick事件。

var dom = document.getElementById("outestA");
dom.onclick = function(){alert("1=" + this.id);};
dom.onclick = function(){alert("2=" + this.id);};

1.4 使用W3C的标准的addEventListener和removeEventLinstener。

// type:事件类型,不含"on",比如"click""mouseover""keydown";
// 而attachEvent的事件名称,含含"on",比如"onclick""onmouseover""onkeydown";
// listener:事件处理函数
// useCapture是事件冒泡,还是事件捕获,默认false,代表事件冒泡类型
addEventListener(type, listener, useCapture);
var dom = document.getElementById("outestA");  
dom.addEventListener('click', a, false);  

function a()  
{   
    alert(this.id);//outestA  
}

同一个事件只能绑定一次。

二、事件处理的函数顺序 
addEventListener添加多个事件之后,是按照添加的顺序来执行。先添加的事件先执行,后添加的事件后执行。(注意,必须是同一个事件,例如onclick事件)

三、事件冒泡和事件捕获 
我们都知道html标签是可以嵌套的,形成类似于树的层级关系。如下代码:

<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
    <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
        <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
    </div>
</div>

如果点击了最内侧的outC,那么外侧的outB和outC算不算被点击了呢?很显然算,不然就没有必要区分事件冒泡和事件捕获了,这一点各个浏览器厂家也没有什么疑义。假如outA、outB、outC都注册了click类型事件处理函数,当点击outC的时候,触发顺序是A–>B–>C,还是C–>B–>A呢?如果浏览器采用的是事件冒泡,那么触发顺序是C–>B–>A,由内而外,像气泡一样,从水底浮向水面;如果采用的是事件捕获,那么触发顺序是A–>B–>C,从上到下,像石头一样,从水面落入水底。

四、DOM事件流 
DOM事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。这个过程很类似于Struts2框中的action和Interceptor。当发出一个URL请求的时候,先调用前置拦截器,其次调用action,最后调用后置拦截器。

<script>

    window.onload = function(){
        var outA = document.getElementById("outA");  
        var outB = document.getElementById("outB");  
        var outC = document.getElementById("outC");  

        // 目标(自身触发事件,是冒泡还是捕获无所谓)
        outC.addEventListener('click',function(){alert("target");},true);

        // 事件冒泡
        outA.addEventListener('click',function(){alert("bubble1");},false);
        outB.addEventListener('click',function(){alert("bubble2");},false);

        // 事件捕获
        outA.addEventListener('click',function(){alert("capture1");},true);
        outB.addEventListener('click',function(){alert("capture2");},true); 
    };

</script>
<body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
        <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
            <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
        </div>
    </div>
</body>

当点击outC的时候,依次打印出capture1–>capture2–>target–>bubble2–>bubble1。到这里是不是可以理解addEventListener(type,handler,useCapture)这个API中第三个参数useCapture的含义呢?useCapture=false意味着:将事件处理函数加入到冒泡阶段,在冒泡阶段会被调用;useCapture=true意味着:将事件处理函数加入到捕获阶段,在捕获阶段会被调用。从DOM事件流模型可以看出,捕获阶段的事件处理函数,一定比冒泡阶段的事件处理函数先执行。

五、阻止事件冒泡和事件捕获。 

默认情况下,多个事件处理函数会按照DOM事件流模型中的顺序执行。如果子元素上发生某个事件,不需要执行父元素上注册的事件处理函数,那么我们可以停止捕获和冒泡,避免没有意义的函数调用。前面提到的5种事件绑定方式,都可以实现阻止事件的传播。由于第5种方式,是最推荐的做法。所以我们基于第5种方式,看看如何阻止事件的传播行为。IE8以及以前可以通过 window.event.cancelBubble=true阻止事件的继续传播;IE9+/FF/Chrome通过event.stopPropagation()阻止事件的继续传播。

<script>
    window.onload = function(){
        var outA = document.getElementById("outA");  
        var outB = document.getElementById("outB");  
        var outC = document.getElementById("outC");  

        // 目标
        outC.addEventListener('click',function(event){
            alert("target");
            event.stopPropagation();
        },false);

        // 事件冒泡
        outA.addEventListener('click',function(){alert("bubble1");},false);        outB.addEventListener('click',function(){alert("bubble2");},false);

        // 事件捕获
        outA.addEventListener('click',function(){alert("capture1");},true);        outB.addEventListener('click',function(){alert("capture2");},true);      

    };
</script>
<body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
        <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
            <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
        </div>
    </div>
</body>

当点击outC的时候,依次打印出capture1–>capture2–>target;取消冒泡/阻止蔓延: e.stopPropagation()

六、 利用冒泡:

      优化: 尽量减少事件监听的个数:

为什么: 浏览器触发事件靠遍历,事件监听越多,遍历时间越长,

导致响应速度变慢

     如何: 利用冒泡:

 如何利用: 如果多个平级子元素,要绑定相同的事件时,

其实只要在父元素绑一次,所有子元素,就可共用!

  为什么: 冒泡

2个难题:

   1. 获得目标元素:

      错误: this, this已经指父元素,不再指子元素

      正确:e.target 始终记录着最初点击的目标元素,不随冒泡而改变

   2. 目标元素不一定是想要的:

         在处理函数中,先判断当前目标元素的特征是否符合要求,再决定是否继续执行。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值