Javascript中的DOM的事件合集-事件流·事件委托·取消事件冒泡和捕获

DOM的事件-事件流·事件委托·取消事件冒泡和捕获

前言

当有以下图片的内容时,如果我们用鼠标点击中间3方框,是不是也同时点击了外面的1、2方框,所以这个时候也会产生一个顺序的问题,那么究竟是以3->2->1由内到外的触发形式?还是以1->2->3由外到内的触发形式呢?故此前者就是事件的冒泡,后者为事件的捕获。
在这里插入图片描述

事件的冒泡(Bubble)

  • 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就是说事件应该在冒泡阶段执行。

下面通过DOM0的写法给元素 绑定事件处理回调函数来具体具体演示说明:

    <div id="box1">
        <div id="box2">点我!!!</div>
    </div>
    <script>
        var box1 = document.getElementById("box1");
        var box2 = document.getElementById("box2");
        var body = document.querySelector("body");
        //给box1、box2、body、document、window分别绑定事件处理回调函数
        box1.onclick = function () {
            console.log("我是外面的green的Box!");
        }

        box2.onclick = function () {
            console.log("我是里面的lightbule的Box!");
        }
        body.onclick = function () {
            console.log("body");
        }
        document.onclick = function () {
            console.log("document");
        }
        window.onclick = function () {
            console.log("window");
        }
    </script>

下面是CSS样式部分

        #box1 {
            width: 300px;
            height: 300px;
            background-color: lightgreen;
            overflow: hidden;//触发BFC
        }

        #box2 {
            width: 100px;
            height: 100px;
            background-color: lightblue;
            margin: 100px auto;
            text-align: center;
            line-height: 100px;
        }
  • 效果如下,当点击中间box时,会依次打印如下:
    在这里插入图片描述
  • 可以看见当前事件冒泡的顺序为:lightbule -> green-> body -> window由内向外传播的方式
  • ie9+(现代浏览器)中所有事件会一直冒泡到window上
  • 故此ie8及以下没有捕获阶段

DOM1的写法addEventListener('事件名', 回调函数, false),其中第三个参数false是默认开启事件冒泡,反之就是关闭事件冒泡:

box1.addEventListener('click',function(){
console.log("我是外面的green的Box!");
}, false);

box2.addEventListener('click',function(){
console.log("我是里面的lightbule的Box!");
}, false);
body.addEventListener('click',function(){
console.log("body");
}, false);
document.addEventListener('click',function(){
console.log("document");
}, false);
window.addEventListener('click',function(){
console.log("window");
}, false);

在这里插入图片描述


事件的捕获

  • 网景公司认为事件应该是由外向内传播的,也就是当事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素

下面通过DOM1中的addEventListener的写法给元素 绑定事件处理回调函数来具体具体演示说明:

 box1.addEventListener('chilk',function(){
     console.log("我是外面的green的Box!");
 }, true);

 box2.addEventListener('chilk',function(){
     console.log("我是外面的lightbule的Box!");
 }, true);
 body.addEventListener('chilk',function(){
     console.log("body");
 }, true);
 document.addEventListener('chilk',function(){
     console.log("document");
 }, true);
 window.addEventListener('chilk',function(){
     console.log("window");
 }, true);

在这里插入图片描述

  • 可以看见当前事件捕获的顺序为:window -> body -> green -> lightbule 由外到内的方式和冒泡的方式相反

事件传播的三个阶段

W3C综合了两个公司的方案,将事件传播分成了以下三个阶段:

  1. 事件捕获
  2. 目标阶段
  3. 冒泡阶段

捕获阶段

  • 在捕获阶段时,从外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件

目标阶段

  • 事件捕获到目标元素,捕获结束开始在目标元素上触发

冒泡阶段

  • 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件

通过DOM0的写法和DOM2addEventListener第三个参数为true写法证明该阶段执行顺序:

 <script>
        var box1 = document.getElementById("box1");
        var box2 = document.getElementById("box2");
        var body = document.querySelector("body");
        /* ------冒泡阶段的代码-------- */
        box1.onclick = function () {
            console.log("冒泡:我是外面的green的Box!");
        }

        box2.onclick = function () {
            console.log("冒泡:我是里面的lightbule的Box!");
        }
        body.onclick = function () {
            console.log("冒泡:body");
        }
        document.onclick = function () {
            console.log("冒泡:document");
        }
        window.onclick = function () {
            console.log("冒泡:window");
        }

        /* ------捕获阶段的代码-------- */
        box1.addEventListener('click',function(){
            console.log("捕获:我是外面的green的Box!");
        }, true);

        box2.addEventListener('click',function(){
            console.log("捕获:我是里面的lightbule的Box!");
        }, true);
        body.addEventListener('click',function(){
            console.log("捕获:body");
        }, true);
        document.addEventListener('click',function(){
            console.log("捕获:document");
        }, true);
        window.addEventListener('click',function(){
            console.log("捕获:window");
        }, true);
    </script>

在这里插入图片描述


事件委托

  • 事件委托指将绑定事件处理回调函数给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
  • 事件委托是利用了冒泡,通过事件委托可以减少事件处理函数绑定的次数,提高程序的性能

target || currentTarget

target

  • target返回触发此事件的元素
    也是事件委托的例子具体例子:
    <ul id="box">
        <li>江流</li>
        <li>心猿</li>
        <li>木龙</li>
        <li>刀圭</li>
        <li>意马</li>
    </ul>
    <script>
        var ul = document.getElementById("box");
        var lis =  document.getElementsByTagName("li");
        var li = Array.prototype.slice.call(lis);//slice()方法使lis返回一个数组
        ul.onclick = function (event) {//给事件委托绑定事件处理回调函数
            var e = event || window.event;//兼容IE8及以下的浏览器
            var target = e.target || e.srcElement;//兼容火狐浏览器
            console.log(li.indexOf(target)+"->"+target.innerText);//获取点击li元素的下标和文字
        }
    </script>

在这里插入图片描述


currentTarget

  • currentTarget返回事件监听器触发该事件的元素
    <ul id="box">
        <li>江流</li>
        <li>心猿</li>
        <li>木龙</li>
        <li>刀圭</li>
        <li>意马</li>
    </ul>

    <script>
        var ul = document.getElementById("box");
        ul.onclick = function (event) {//事件委托
            var e = event || window.event;
            var currentTarget = e.currentTarget;
            console.log(currentTarget);
        }
    </script>

在这里插入图片描述


取消事件的冒泡和捕获

  • 一般的事件都有冒泡,但是focus、onblur、scroll没有冒泡

bubbles

  • bubbles可以用来检查一个事件是否可以冒泡
  box2.addEventListener('click', function (e) {
      console.log(e.bubbles);
      console.log("我是里面的lightbule的Box!");
  }, false);

在这里插入图片描述


stopPropagation()

  • stopPropagation()可以阻止事件的冒泡和捕获
  • IE8及以下不支持
<body id="body">
    <div id="box1">
        <div id="box2">点我!!!</div>
    </div>

    <script>
        box1.addEventListener('click', function () {
            console.log("我是外面的green的Box!");
        }, false);

        box2.addEventListener('click', function () {
            console.log("我是里面的lightbule的Box!");
        }, false);
        body.addEventListener('click', function (e) {
        var e = e || window.event;
            e.stopPropagation();
            console.log("body");
        }, false);
        document.addEventListener('click', function () {
            console.log("document");
        }, false);
        window.addEventListener('click', function () {
            console.log("window");
        }, false);
    </script>
</body>

在这里插入图片描述


stopImmediatePropagation()

  • stopImmediatePropagation() 方法阻止监听同一事件的其他事件监听器被调用。

  • 如果多个事件监听器被附加到相同元素的相同事件类型上,当此事件触发时,它们会按其被添加的顺序被调用。

  • 如果在其中一个事件监听器中执行 stopImmediatePropagation(),那么剩下的事件监听器都不会被调用。

  • 也就是说在原本stopPropagation()基础之上,能够去阻止其他事件监听器被调用

  • IE8及以下不支持


cancelBubble

  • cancelBubble可以阻止事件的冒泡和捕获
  • 用法:e.cancelBubble = true
  • 如果需要阻止其他事件监听器被调用则需要把函数单独命名然后设置为null
<body id="body">
    <div id="box1">
        <div id="box2">点我!!!</div>
    </div>

    <script>
        box2.addEventListener('click', function () {
            console.log("我是里面的lightbule的Box!");
        }, false);

        box1.addEventListener('click', function (e) {
            // e.stopPropagation();
            console.log("我是外面的green的Box!");
        }, false);


        body.addEventListener('click', function (e) {
            var e = e || window.event;
            e.cancelBubble = true
            console.log("body");
        }, false);
        document.addEventListener('click', function (e) {
            var e = e || window.event;
            e.stopPropagation();
            console.log("document");
        }, false);
        window.addEventListener('click', function () {
            console.log("window");
        }, false);

    </script>
</body>

在这里插入图片描述


兼容写法

   function cancelBubble(e) {
       var e = e || window.event;
       if (e.stopPropagation) {
           e.stopPropagation();
       } else {
           e.cancelBubble = true;
       }
   }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值