冒泡事件和捕获事件以及阻止冒泡和捕获方法的详解

(1)相关概念
事件流的概念:事件流所描述的就是从页面中接受事件的顺序。
事件流也有两种,分别是事件冒泡和事件捕获,现行的主流是事件冒泡。
以上就是通过原生js将每一个div都绑定了一个事件,且通过useCapture这个参数将事件类型设置为true(捕获)或者
false(默认为false,冒泡)
需要注意的是:更改事件流的属性,只能通过原生js中的方法,因为只有原生js中有更改事件流属性的参数,其它没有。jquery的事件流是冒泡型的,里面的事件都是冒泡型的,没法更改事件流的属性,因为方法中没有更改事件流的参数。

冒泡事件定义:
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。

事件委托机制:
由冒泡事件衍生出的事件委托机制,既然事件是冒泡传递的,那可以让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理。就是将子元素的事件处理程序绑定到父类上,例如常见的ul>li> a列表标签的写法应用。

此处给出一个委托机制的例子:
源程序:
<ul>
   <li id="ll">选项一</li>
   <li>选项二</li>
   <li>选项三</li>
   <li>选项四</li>
</ul>
第一种写法:直接利用子元素的选择,没有绑定父元素,没有实现委托机制
$("li").mouseover(function () {
console.log(event.target);
$(this).css("background-olor","#ffff00").siblings().css("background-color","#1d7b15");
});
效果:

 


第二种写法:委托父类,实现委托机制,但是内容判断上通过原生js实现 
$("ul").on("mouseover", function () {
    console.log(event.target);
    var lis = document.getElementsByTagName("li");
    for (var i = 0; i < lis.length; i++) {
        if (event.target && event.target == lis[i]) {
            $(event.target).css("background-color", "#ffff00").siblings().css("background-color", "#1d7b15");
        }
    }
});
效果:
 

第三种写法:委托父类,实现委托机制,但是通过过滤器筛选出要作用的子元素li,这种方法最简单。
$("ul").on("mouseover","li", function (event) {
    $(event.target).css("background-color", "#ffff00").siblings().css("background-color", "#1d7b15");
});

$(selector).on(event,childSelector,data,function,map)
 childSelector 可选。规定只能添加到指定的子元素上的事件处理程序,且不是选择器本身,即就是 对父元素触发事件的一种过滤。
效果:

 

小结:三种方法都可以,建议第三种方法,简单方便。

捕获机制:
事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件。而事件冒泡是自下而上的去触发事件。绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获,true是事件捕获,false是事件冒泡。默认false,即事件冒泡。通常可以用Jquery的e.stopPropagation会阻止冒泡,意思就是到我为止,我的爹和祖宗的事件就不要触发了。

(2)jQuery 提供了两种方式来阻止事件冒泡。
方式一:event.stopPropagation();
        $("#div1").mousedown(function(event){
            event.stopPropagation();
        });
方式二:return false;
        $("#div1").mousedown(function(event){
            return false;
        });
但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。
(3)阻止捕获的方法
stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。
无论事件流中只有捕获还是事件流中只有冒泡,还是说是事件流中既有捕获还有冒泡,event.stopPropagation()都可以阻止事件流的传播顺序。只要是event.stopPropagation()加在哪里,则到哪里就停止运行,停止捕获或者停止冒泡,简单说是,仍然按照正常的混合机制流程走,只是哪里有e.stopPropagation()则这个流程到哪里就停止了。

(4)捕获与冒泡相关例子
源程序:
<div id="div1" class="parent">div1
   <div id="div2" class="child">div2
      <div id="div3">div3
         <div id="div4">div4</div>
      </div>
      
   </div>
</div>



 

(A)只测试捕获情况
<script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");
    var div3 = document.getElementById("div3");
    var div4 = document.getElementById("div4");

    div1.addEventListener("click", function (e) {
        alert("div1::" + e.target);
    }, true);

    div2.addEventListener("click", function (e) {
        alert("div2::" + e.target);
    }, true);
    
    div3.addEventListener("click", function (e) {
        alert("div3::" + e.target);
    }, true);
    
    div4.addEventListener("click", function (e) {
        alert("div4::" + e.target);
    }, true);
</script>
以上的代码中,若是点击最里面的div4区域,则弹窗出现的顺序为:div1--》div2--》div3--》div4,
即使符合捕获条件的。就是先出现最外层捕获,最后才是自己。

(B)事件流中既含有捕获事件有含有冒泡事件的混合情况
<script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");
    var div3 = document.getElementById("div3");
    var div4 = document.getElementById("div4");

    div1.addEventListener("click", function (e) {
        alert("div1::" + e.target);
    }, true);

    div2.addEventListener("click", function (e) {
        alert("div2::" + e.target);
    }, false);

    div3.addEventListener("click", function (e) {
        alert("div3::" + e.target);
    }, true);

    div4.addEventListener("click", function (e) {
        alert("div4::" + e.target);
    }, false);
<script>
这里是事件流中既有冒泡也有捕获
W3C明智地在这场争斗中选择了一个折中的方案:任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段。

 以上的脚本代码中:div1和div3是捕获事件流,div2和div4是冒泡事件流。
 若是点击div4,则结果是:div1--》div3-》div4--》div2
 很明显就是先捕获,然后冒泡。
若是点击div3,则结果为:div1--》div3--》div2
(C)混合情况下阻止捕获情况
<script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");
    var div3 = document.getElementById("div3");
    var div4 = document.getElementById("div4");

    div1.addEventListener("click", function (e) {
        alert("div1::" + e.target);
    }, true);
    div2.addEventListener("click", function (e) {
        alert("div2::" + e.target);
    }, false);
    div3.addEventListener("click", function (e) {
        alert("div3::" + e.target);
        e.stopPropagation(); }, true);

    div4.addEventListener("click", function (e) {
        alert("div4::" + e.target);
    }, false);

这依旧是一种捕获和冒泡共存的情况,若是点击div4,则结果div1---》div3,因为到div3就停止捕获了。
(D)混合情况下阻止冒泡情况
<script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");
    var div3 = document.getElementById("div3");
    var div4 = document.getElementById("div4");
    div1.addEventListener("click", function (e) {
        alert("div1::" + e.target);
    }, true);
    div2.addEventListener("click", function (e) {
        alert("div2::" + e.target);
    }, false);
    div3.addEventListener("click", function (e) {
        alert("div3::" + e.target);
       }, true);
    div4.addEventListener("click", function (e) {
        alert("div4::" + e.target);
	  e.stopPropagation();
    }, false);
此时若是点击div4,则结果为div1—》div3—》div4,因为到div4就已经停止冒泡了。

 小结:
 冒泡是从目标元素往父元素走,捕获是从祖宗元素开始往目标元素走;两个都有的话先捕获再冒泡。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值