• 第三天:js中的事件提高篇(事件流,事件对象,事件委托深层次理解)


    前言

    对于一个html网页来说,html是页面的骨架,css是页面的样式,而js则控制页面元素的行为。本篇我们将学习原生网页界面如何操作元素(监听并绑定事件)。并介绍事件流,事件对象,事件冒泡,以及事件委托这几个点。希望对读者的学习有帮助!

    一,基础部分

    1.1 js监听并绑定事件

    请看以下代码:

        <button>方法监听注册事件</button>
        <script>
            var btn = document.querySelector('button');
            btn.addEventListener('click', function() {
                alert('22');
            })
            btn.addEventListener('click', function() {
                alert('22');
            })
        </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过上述代码可了解:
    第一步:绑定页面元素
    第二步:监听器addEventListener

    e.addEventListener('事件','回调函数') {}
    
    • 1

    这里需要注意的是,之前我们写简单的事件绑定,如e.onclick(),e.onmouse等,在新学习的这种写法中,事件写的内容要在原来的基础上把on去掉。

    1.2 删除事件绑定

    请看以下代码:

            divs[1].addEventListener('click', fn);
            function fn() {
                alert('22');
                divs[1].removeEventListener('click',fn);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    最开始给divs中索引为1的元素绑定了click事件,回调函数为fn。当点击fn后,先弹出‘22’模态框,然后取消了该元素的绑定事件。并执行新的回调函数。

    二,事件流

    2.1 事件流是什么

    首先从字面上理解,事件流指从页面中接收事件的顺序。

    我们知道,js是单线程的脚本语言(JavaScript是一种解释型的脚本语言,C、C++等语言先编译后执行,而JavaScript是在程序的运行过程中逐行进行解释。),当页面中的DOM元素触发事件,浏览器从Window开始从上往下遍历,来查找整个DOM元素。概括为事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流

    2.2 事件流模型

    事件流模型则可以很直观的从原理来为我们呈现事件流,事件流模型分为两个部分:分别是冒泡型事件流,捕获型事件流

    我们知道,网页中元素很多,大部分元素都有父元素,也有部分元素有子元素,那么我们是不是可以把元素看成一棵树(DOM树):
    在这里插入图片描述

    冒泡型事件流:从DOM树的叶子到根,从下到上,范围从小到大遍历;
    捕获型事件流:从DOM树的跟到叶子,从上到下,范围从大到小遍历。

    2.3 捕获与冒泡具体示例

    2.3.1 addEventListener的第三个参数

    刚刚我们已经了解,js中addEventListener的用法。在介绍完冒泡与捕获后,向大家介绍第三个参数:具体格式如下

    e.addEventListener('事件',‘回调函数’,第三个参数)
    
    • 1

    第三个参数是一个布尔值,默认为false,false对应的是冒泡,true代表的是捕获。

    接下来我们利用以下结构来学习捕获与冒泡的具体实例:

        
    • 1
    • 2
    • 3

    在这里插入图片描述

    2.3.1 捕获阶段

    捕获阶段,addEventListener的第三个值是true,请看以下代码:

            var son = document.querySelector('.son');
            son.addEventListener('click', function() {
                alert('son');
            }, true);//捕获阶段
    
            var father = document.querySelector('.father');
            father.addEventListener('click', function() {
                alert('father');
            }, true);//捕获阶段
             document.addEventListener('click', function() {
                alert('document');
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    对子盒子,父盒子先进行获取,然后再绑定事件。理论上,点击son会弹出son模态框,点击father会弹出father模态框。但在捕获阶段:
    点击father时没有任何问题:
    在这里插入图片描述

    点击son时却:
    在这里插入图片描述在这里插入图片描述
    原因:捕获型事件流:从DOM树的跟到叶子,从上到下,范围从大到小遍历。
    点击父元素遍历顺序:father
    点击子元素遍历顺序:father->son,所以点击子元素时会先出现父元素模态框,再出现子元素模态框。
    至于为什么没有出现document的模态框,因为我们没有点document,点的是father所以从father开始遍历。

    2.3.2 冒泡阶段

    捕获阶段,addEventListener的第三个值是false(或者不写,因为默认false),请看以下代码:

            var father = document.querySelector('.father');
            father.addEventListener('click', function() {
                alert('father');
            });
            var son = document.querySelector('.son');
            son.addEventListener('click', function() {
                alert('son');
            });
    
            document.addEventListener('click', function() {
                alert('document');
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    点击father时:
    在这里插入图片描述
    在这里插入图片描述
    点击son时:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    原因:冒泡型事件流:从DOM树的叶子到根,从下到上,范围从小到大遍历
    点击父元素遍历顺序:father->document;
    点击子元素遍历顺序: son->father->document。

    三,事件对象

    3.1 事件对象是什么

    div是一个盒子,为它绑定事件:

            var div = document.querySelector('div');
            div.addEventListener('click', function(event){
                console.log(event);
            })
    
    • 1
    • 2
    • 3
    • 4

    打印event,结果是一个对象:
    在这里插入图片描述
    我们把event称作事件对象。其中,event可以看作是形参,可以任意更改名字。
    这里简单定义一下事件对象:事件对象是事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击的信息,键盘。事件对象存在的前提是事件存在,由系统自动为我们创建

    3.2 事件对象常用的属性和方法

    3.2.1 阻止默认行为

    非常常用!默认行为比如:链接跳转,按钮自动提交等等,我们可以通过事件对象阻止默认行为,下面以阻止链接跳转为例:

    e.preventDefault()
    
    • 1
            var a = document.querySelector('a');
            a.addEventListener('click', function(e) {
                // e.preventDefault();//方法
                // e.returnValue;//属性
                return false;//通用,但不能执行后续代码
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2.2 阻止事件冒泡

    事件冒泡是子到父,当我们为子与父都绑定了点击出现模态框事件,如何取消?见如下代码:

     e.stopPropagation();
    
    • 1
            var father = document.querySelector('.father');
            var son = document.querySelector('.son');
            father.addEventListener('click', function() {
                alert('我是father');
            })
            son.addEventListener('click', function(e) {
                alert('我是son');
                e.stopPropagation();
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    即可成功阻止

    3.2.3 鼠标事件对象

    在这里插入图片描述
    我们有了事件对象,便可通过事件对象获取鼠标的位置。具体如上图,大家也可以拿下面的代码进行实验:

            document.addEventListener('click', function(e) {
                console.log(e.clientX);
                console.log(e.clientY);
    
                console.log(e.pageX);
                console.log(e.pageY);
    
                console.log(e.screenX);
                console.log(e.screenY);
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四,事件委托

    定义:事件委托(事件代理)。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡

    大家请自行编译如下代码:

        <ul>
            <li>子元素</li>
            <li>子元素</li>
            <li>子元素</li>
            <li>子元素</li>
            <li>子元素</li>
        </ul>
    
        <script>
            //给父节点添加监听器
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {
                alert('弹出');
                e.target.style.backgroundColor = 'pink';
            })
        </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    效果:当我们点击每个子元素li时候,都会弹出模块框‘弹出’。原因:
    在这里插入图片描述
    点击子元素后,由于是冒泡阶段(默认false),所以遍历顺序:子元素->父元素->document。所以,点击子元素后,会触发父元素,于是就会触发模块狂的弹出。

    注意:使用“事件委托”时,并不是说把事件委托给的元素越靠近顶层就越好。事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时。如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失。

    后记

    本节我们对事件流,事件对象,事件委托等内容进行了讲解。后续会更新更多底层原理及应用,谢谢喜欢,欢迎关注!

  • 相关阅读:
    快速掌握正则表达式
    趋势的转换,数字化转型的基本逻辑经历了怎样的变化?
    ES6------04let经典案例实现
    SpringMVC入门宝典(八)SpringMVC异常处理
    600w播放,80w涨粉,B站UP主恰饭B站粉丝竟刷屏感谢甲方!
    Android 13 第一个开发者预览版本来了,网友直呼:Android 12 还没透
    vue-cropper在ie11下选择本地图片后,无显示、拒绝访问的问题
    JAVA:实现合并已排序的单链表算法(附完整源码)
    关于我的人生(假如我工作13年就能得到3w个花西币)
    性能指标都不了解,如何做性能测试?
  • 原文地址:https://blog.csdn.net/zxdznyy/article/details/127100186