zoukankan      html  css  js  c++  java
  • 浅谈js的事件冒泡和事件捕获

    本文地址:https://www.cnblogs.com/christineqing/p/7607113.html

    前言:

       这篇文章起源于上次工作上的原因,在事件上出的bug,所以就抽空写出一篇,也便于自己以后查阅,如若有幸被您阅读的话,小妹备感荣幸,文章仅为个人理解,如果内容有误的还望海涵,在您时间还方便的时候,希望能告知小妹!谢谢!

     什么是事件?

       事件是文档和浏览器窗口中发生的特定的交互瞬间。 事件是javascript应用跳动的心脏,也是把所有东西黏在一起的胶水,当我们与浏览器中web页面进行某些类型的交互时,事件就发生了。

     事件可能是用户在某些内容上的点击,鼠标经过某个特定元素或按下键盘上的某些按键,事件还可能是web浏览器中发生的事情,比如说某个web页面加载完成,或者是用户滚动窗口或改变窗口大小。

    什么是事件流:

       事件流描述的是从页面中接受事件的顺序,但有意思的是,微软(IE)和网景(Netscape)开发团队居然提出了两个截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling),而Netscape的事件流是事件捕获流(event capturing)。

       

     第一种:事件冒泡

           IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点,看一下以下示例:

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body onclick="bodyClick()">
    
        <div onclick="divClick()">
            <button onclick="btn()">
                <p onclick="p()">点击冒泡</p>
            </button>
        </div>
        <script>
           
           function p(){
              console.log('p标签被点击')
           }
            function btn(){
                console.log("button被点击")
            }
             function divClick(event){
                 console.log('div被点击');
             }
            function bodyClick(){
                console.log('body被点击')
            }
    
        </script>
    
    </body>
    </html>
    复制代码

    接下来我们点击一下页面上的p元素,看看会发生什么:

       正如上面我们所说的,它会从一个最具体的的元素接收,然后逐级向上传播, p=>button=>div=>body..........事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。

     第二种:事件捕获

             网景公司提出的事件流叫事件捕获流。

              事件捕获流的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件,针对上面同样的例子,点击按钮,那么此时click事件会按照这样传播:(下面我们就借用addEventListener的第三个参数来模拟事件捕获流)

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div>
        <button>
            <p>点击捕获</p>
        </button>
    </div>
    <script>
        var oP=document.querySelector('p');
        var oB=document.querySelector('button');
        var oD=document.querySelector('div');
        var oBody=document.querySelector('body');
    
        oP.addEventListener('click',function(){
            console.log('p标签被点击')
        },true);
    
        oB.addEventListener('click',function(){
            console.log("button被点击")
        },true);
    
        oD.addEventListener('click',  function(){
            console.log('div被点击')
        },true);
    
        oBody.addEventListener('click',function(){
            console.log('body被点击')
        },true);
    
    </script>
    
    
    
    </body>
    </html>
    复制代码

    同样我们看一下后台的打印结果:

    正如我们看到的,和冒泡流万全相反,从最不具体的元素接收到最具体的元素接收事件  body=>div=>button=>p 

    DOM事件流:

          ‘DOM2级事件’规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应。

       在DOM事件流中,事件的目标在捕获阶段不会接收到事件,这意味着在捕获阶段事件从document到<p>就停止了,下个阶段是处于目标阶段,于是事件在<p>上发生,并在事件处理中被看成冒泡阶段的一部分,然后,冒泡阶段发生,事件又传播回document。

    下面是我们模拟它的示例:

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码

    看看后台给出什么结果:

    就是这样一个流程,先捕获,然后处理,然后再冒泡出去。

     关于DOM 2级事件处理程序:

         DOM 2级事件定义了两方法:用于处理添加事件和删除事件的操作: 添加事件 addEventListener()     删除事件  removeEventListener()

       所有DOM节点中都包含这两个方法,并且他们都包含3个参数: (1) 要处理的事件方式(例如:click,mouseover,dbclick.....) (2)事件处理的函数,可以为匿名函数,也可以为命名函数(但如果需要删除事件,必须是命名函数) (3)一个布尔值,代表是处于事件冒泡阶段处理还是事件捕获阶段(true:表示在捕获阶段调用事件处理程序;false:表示在冒泡阶段调用事件处理程序)

      使用DOM 2级事件处理程序的主要好处是可以添加多个事件处理程序,事件处理会按照他们的顺序触发,通过addEventListener添加的事件只能用removeEventListener来移除,移除时传入的参数与添加时使用的参数必须相同,这也意味着添加的匿名函数将无法移除,(注意:我们默认的第三个参数都是默认false,是指在冒泡阶段添加,大多数情况下,都是将事件处理程序添加到事件的冒泡阶段,这样可以最大限度的兼容各个浏览器

    复制代码
    //这是一个DOM 2级事件 添加事件最简单的方式(此时添加的是一个匿名函数)
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>按钮</button> <script> var btn=document.querySelector('button'); btn.addEventListener('click',function(){ console.log('我是按钮') },false) //当第三个参数不写时,也是默认为false(冒泡时添加事件) </script> </body> </html>
    复制代码

    那么我们试试命名函数:

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <button>按钮</button>
        <script>
            var btn=document.querySelector('button');
            btn.addEventListener('click',foo,false);
            function foo(){
                console.log('我是按钮')
            }
    //其实操作就是把写在里面的函数拿到了外面,而在原来的位置用函数名来代替 </script> </body> </html>
    复制代码

    那么我们添加两个事件试试:

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <button>按钮</button>
        <script>
            var btn=document.querySelector('button');
    //第一个事件 btn.addEventListener('click',foo,false); function foo(){ console.log('我是按钮') }
    //第二个事件 btn.addEventListener('click',newFoo,false); function newFoo(){ console.log('我是新按钮') } </script> </body> </html>
    复制代码

    那么我们看看后台有没有执行,执行顺序是怎样的:

    所以说,我们添加两个事件是可以的,事件的顺序就是按照我们程序写的顺序执行的

    那我们试试DOM 0级事件处理程序

    复制代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <button onclick="foo()"  onclick="newFoo()">按钮</button>
        <script>
            function foo(){
                console.log(2)
            }
            function newFoo(){
                console.log(9)
            }
        </script>
    </body>
    </html>
    复制代码

    看一下结果:

    只执行了第一个事件,第二个被忽略,这并不是我们想要的结果,而addEventLiener是会把两个事件都去执行的。

    结尾:

       以上就是事件冒泡,事件捕获,dom事件流,dom2级事件流的所有内容,谢谢阅读!

  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/jeff-zhu/p/11508556.html
Copyright © 2011-2022 走看看