js中的冒泡,捕获以及事件委托

之前学习冒泡和捕获时有些囫囵吞枣,加之很长一点时间没有做过dom类的工作,所以就遗忘了.这次因为项目中有一些dom操作需要我来写,所以又需要去研究一下.故总结出一些我个人的见解跟大家分享.如有理解不对的地方,欢迎各位不吝赐教,批评佐证.

什么是冒泡和捕获

冒泡和捕获是dom中的两种事件流,现代浏览器基本都遵循这两种事件流方式.

上面这句话可能比较抽象,废话不多说,那直接上代码,让我们通过现象去了解本质

    <div id='far'>
        <div id='son'></div>
    </div>
    //js es6
    let far = document.getElementById('far');
    let son = document.getElementById('son');
    far.addEventListener('click',()=>console.log('我是far'));
    son.addEventListener('click',()=>console.log('我是son'));

    //执行以上代码,当点击son时,你会发现far的点击事件也被触发了.

冒泡阶段

很多人把这种现象叫做事件冒泡,起初我也是这样认为的.但是当我学习了事件流中的冒泡模型和捕获模型后,我就改变了想法(我认为,冒泡和捕获只是事件流执行的两种规则,后面会具体说).因为当你在点击son的时候,其实你点击的位置也在far的范围内,所以far的点击事件被触发是正常的.
那么也就可以很好的理解,为什么当我们不给son注册点击事件,而我们还是在son的范围内点击鼠标时,far依然会触发.

那么说到这里,我们就可以谈一谈冒泡啦.

此时,我们需要先考虑一个问题:

为什么先触发的不是far,而是son呢?

要回答这个问题,首先我们要知道,当事件触发时,事件会分为两个阶段,一个是冒泡阶段,另一个则是捕获阶段.整个事件流当中,先执行捕获,后执行冒泡.上面事例代码执行结果的原因就是事件是在冒泡阶段执行的(w3c在注册事件当中规定默认情况下在冒泡阶段执行).

在冒泡的阶段的执行顺序是按照 :从事件源 —>document 依次执行的
在刚才的例子当中的体现则是 son —>far(由内到外)

而捕获阶段则是: document—>事件源 依次执行
在下面例子中体现则是far—>son(从外到内)

    //js es6
    let far = document.getElementById('far');
    let son = document.getElementById('son');
    far.addEventListener('click',()=>console.log('我是far'),true);
    son.addEventListener('click',()=>console.log('我是son'));

    //addEventListenner函数的第三个参数可以控制事件在冒泡/捕获阶段执行. 当为false是,在冒泡阶段执行,为true时,则在捕获阶段执行.

捕获阶段

以上就是所谓的冒泡和捕获.
为了更好的理解前面所说的内容,我们来通过一段代码分析来加深理解

    <ul id="ul">
        <li id='one'>222</li>
        <li id='two'><a href="#" id='only'>111</a></li>
        <li id='three'>333</li>
    </ul>
    const ul = document.getElementById('ul');
    const li = document.getElementById('two');
    const a = document.getElementById('only')

    a.addEventListener(
        'click',
        ()=>console.log('我是a标签'),
        false);//冒泡阶段执行

    li.addEventListener(
        'click', 
        ()=>console.log('我是li标签'),
        false);//冒泡阶段执行

    ul.addEventListener(
        'click',
        ()=>console.log('我是ul标签'),
        true);//捕获阶段执行

从以上代码可以看出来, 三个dom元素具有子父级的关系

ul > li > a

当我点击a标签时,执行结果如下:

ul —> a —>li

捕获,冒泡示例

代码分析:

因为我手动设置ul在捕获阶段执行,li 和 a 在冒泡阶段执行.而前面我们讲过,事件流是先执行捕获后执行冒泡的.

说到这里,相信大家已经能够清晰的了解什么是冒泡和捕获了吧.

事件委托

我们来假设一个场景,我要给一个ul列表中的每一个li设置点击事件,应该怎么做呢?

一般做法 : 就是给每一个li添加一个点击事件. 但是这样做的弊端较大,冗余代码多,占用内存多等问题.

更好的办法 : 使用事件委托. 利用我们前面说到的,给父元素注册点击事件,点击内部子元素时,也会触发父元素的事件.代码如下:

    <ul id="ul">
        <li id='one'>111</li>
        <li id='two'>222</li>
        <li id='three'>333</li>
    </ul>
    let ul = document.getElementById('ul');

    ul.addEventListener('click',(e)=>{
        let ev = e || window.event; 
        let tag = ev.target||ev.srcElement;
        switch(tag.id){
            case 'one':
                console.log("one")
            break;
            case 'two':
                console.log('two')
            break;
            case 'three':
                console.log('three')
            break;
        }
    },true);

:
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值