zoukankan      html  css  js  c++  java
  • JS事件流的一些理解

    昨晚和今天在复习JS事件流,那么,就来归纳总结JS事件流的一些知识点吧.首先,我们先来讲述下,当一个节点产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,路径通过的节点都会收到该事件,这个传播过程称为DOM事件流.

    首先,我们先来解释下什么是事件:

    Javascript和HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口发生的一些特定的交互瞬间.可以使用监听器来预定事件,以便事件发生时执行相应的代码.

    那么事件流又是什么呢?

    事件流描述的就是从页面中接收事件的顺序,而早期的IE与Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而NetScape的事件流就是事件捕获.

    那么,接下来我们就介绍下事件冒泡与事件捕获.

    IE提出的事件流是事件冒泡,即从下至上,从目标触发的元素逐级向上传播,直到window对象.

    而Netscape的事件流就是事件事件捕获,即从document逐级向下传播到目标元素.

    而DOM2事件的事件流则包含三个阶段:1).事件捕获阶段;2).处于目标阶段;3).事件冒泡阶段

    接下来,我们来讲述下DOM2中的一些内容.

    DOM2中定义了两个方法:

    1.addEventListener() -- 添加事件侦听器

    2.removeEventListener() -- 删除事件侦听器

    函数均有三个参数,第一个参数是要处理的事件名,第二个参数是作为事件处理程序的函数,第三个参数是一个布尔值,默认为false表示使用冒泡机制,true表示捕获机制.

    <div id="btn">点这个</div>
    <script>
    var btn=document.getElementById("btn");
    btn.addEventListener("click",ljy,false);
    btn.addEventListener("click",ljy1,false);
    function ljy(){
    console.log("ljy");
    }
    function ljy1(){
    console.log('ljy1')
    }
    </script>

    这时候两个事件处理程序都可以成功触发,这说明了我们可以绑定多个事件处理程序,但是注意,如果使用了一模一样的监听方式的话,会发生覆盖的,即同样的事件和事件流机制下相同方法只会触发一次.

    <div id="btn">点这个</div>
    <script>
    var btn=document.getElementById("btn");
    btn.addEventListener("click",ljy,false);
    btn.addEventListener("click",ljy,false);
    function ljy(){
    console.log("ljy");
    }
    </script>

    这时,ljy只会执行一次.而继续,我们把div扩展到3个.

    <div id="btn3">
    btn3
    <div id="btn2">
    btn2
    <div id="btn1">
    btn1
    </div>
    </div>
    </div>
    <script>
    let btn1 = document.getElementById('btn1');
    let btn2 = document.getElementById('btn2');
    let btn3 = document.getElementById("btn3");
    btn1.addEventListener("click",function{
    console.log(1);
    },true)
    btn1.addEventListener("click",function{
    console.log(2)},true)
    btn1.addEventListener("click",function{
    console.log(3);
    },true)
    </script>

    那么,这个执行顺序就是3->2->1了,最外层的btn最先触发,因为addEventListener最后一个参数是true,捕获阶段进行处理.

    btn1.addEventListener('click',function(){
        console.log('btn1捕获')
    }, true)
    btn1.addEventListener('click',function(){
        console.log('btn1冒泡')
    }, false)
    
    btn2.addEventListener('click',function(){
        console.log('btn2捕获')
    }, true)
    btn2.addEventListener('click',function(){
        console.log('btn2冒泡')
    }, false)
    
    btn3.addEventListener('click',function(){
        console.log('btn3捕获')
    }, true)
    btn3.addEventListener('click',function(){
        console.log('btn3冒泡')
    }, false)

    那么这个执行顺序就是,btn3捕获,btn2捕获,btn1捕获,btn1冒泡,btn2冒泡,btn3冒泡

    我们看到先执行捕获阶段的处理程序,我们把顺序换一下再看看允许结果.

    btn1.addEventListener('click',function(){
        console.log('btn1冒泡')
    }, false)
    btn1.addEventListener('click',function(){
        console.log('btn1捕获')
    }, true)
    
    btn2.addEventListener('click',function(){
        console.log('btn2冒泡')
    }, false)
    btn2.addEventListener('click',function(){
        console.log('btn2捕获')
    }, true)
    
    btn3.addEventListener('click',function(){
        console.log('btn3冒泡')
    }, false)
    btn3.addEventListener('click',function(){
        console.log('btn3捕获')
    }, true)

    点击btn1的时候,这个执行顺序就是:

    btn3捕获-->btn2捕获-->btn1冒泡-->btn1捕获-->btn2冒泡-->btn3冒泡

    点击的是btn2的时候,这个执行顺序为:

    btn3捕获-->btn2冒泡-->btn2捕获-->btn3冒泡

    点击btn3的时候,这个执行顺序为:

    btn3冒泡->btn3捕获

    需要记住这个点:非目标元素捕获-目标元素代码顺序-非目标元素冒泡(最开始看的时候,还有点不太能明白)

    阻止冒泡

    有时候,我们需要点击事件不再继续向上冒泡,我们在btn2上加上stopPropagation函数,阻止程序冒泡.

    btn1.addEventListener('click',function(){
        console.log('btn1冒泡')
    }, false)
    btn1.addEventListener('click',function(){
        console.log('btn1捕获')
    }, true)
    
    btn2.addEventListener('click',function(){
        console.log('btn2冒泡')
    }, false)
    btn2.addEventListener('click',function(ev) {
        ev.stopPropagation();
        console.log('btn2捕获')
    }, true)
    
    btn3.addEventListener('click',function(){
        console.log('btn3冒泡')
    }, false)
    btn3.addEventListener('click',function(){
        console.log('btn3捕获')
    }, true)

    btn3捕获-->btn2捕获,可以看到btn2捕获阶段进行后不再继续往下执行.

    接下来,我们顺带说下事件委托

    如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因此我们通过事件委托来进行优化,事件委托利用的就是冒泡原理.

    <ul>
        <li>l</li>
        <li>j</li>
        <li>y</li>
        <li>1</li>
        <li>2</li>
    </ul>
    <script>
        var listen= document.getElementsByTagName('li')
        for(let index=0;index<listen.length;index++){
            listen[index].addEventListener('click',function (ev){
            console.log(ev.currentTarget.innerHTML)
        })
        }
        </script>

    按照上述代码,如果我们给每一个li都会绑定一个事件,但是如果这个时候li是动态渲染的,数据又特别大的时候,若是新增的时候,我们还得重新绑定,繁琐又耗能.这时我们可以将绑定事件委托到li的父级元素,ul上.

    var ulee=document.getElementByTagName('ul')
    ulee[0].addEventListener('click',function(ev){
    console.log(ev.target.innerHTML)
    })

    上面的两种代码中,我们分别用了currentTarget与target,那么这两者的区别在哪里呢?

    首先,target返回触发的元素,不一定是绑定事件的元素,而currentTarget返回的是绑定事件的元素

    事件委托的出现,可以提高性能,减少占用的内存空间.并且即使新增加了元素也不需要杂糅化的添加.

    还有个关于这方面看到的过的一道题,事件如何先捕获后冒泡呢?

    在DOM标准事件模型中,是先捕获后冒泡的.但是如果要实现先冒泡后捕获的结果,对于同一个事件,监听捕获与冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获事件.

    当然也有些不支持冒泡的事件:鼠标事件:mouseleave mouseenter 焦点事件:blur focus UI事件:scroll resize.

  • 相关阅读:
    学习笔记(4)---JQuery
    学习笔记---ES6
    angular.js的学习笔记(1)
    vue.js学习笔记(1)
    HTML5“爱心鱼”游戏总结
    学习笔记(3)---综合
    学习笔记(2)---CSS中的易混淆点
    学习笔记(1)----水平垂直居中的方法
    javascript:void(0)是什么意思
    private Int32? m_shopid;
  • 原文地址:https://www.cnblogs.com/ljylearnsmore/p/14520154.html
Copyright © 2011-2022 走看看