• 技术文章 >web前端 >js教程

    深入了解JavaScript中的事件冒泡与捕获

    青灯夜游青灯夜游2022-08-04 21:02:45转载150
    本篇文章带大家了解下事件冒泡与捕获,一次搞懂js事件目标查找方式(冒泡与捕获)、事件代理、e.target与e.currentTarget的区别、阻止冒泡与捕获、取消默认事件,希望对大家有所帮助!

    一、EventTarget 事件目标的查找方式(冒泡与捕获)

    事件目标指的是绑定事件的元素,elemet.addEventListener(‘click’,function(){}) 这里的 elemet 就是事件目标。

    冒泡与捕获:

    addEventListener(type,listener,useCapture) 简单分析:

    参数useCapture解析:

    重点!!一个事件目标的触发,整个过程分为两个阶段(捕获与冒泡)。 useCapture 这个值决定事件目标的触发在哪个阶段执行。

    冒泡与捕获的顺序分析:

    1.png

    代码演示:

    <body>
        <div id="div1">
            这是div1
            <div id="div2">
                这是div2
                <div id="div3">这是div3</div>
            </div>
        </div>
        <script>
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.addEventListener('click',function(){
                console.log("这是div1的点击事件");
            },false);
            div2.addEventListener('click',function(){
                console.log("这是div2的点击事件");
            },false);
            div3.addEventListener('click',function(){
                console.log("这是div3的点击事件");
            },false);
        </script>
    </body>

    当我们点击div3,如下从控制台结果可以看出,这里的事件都是在冒泡阶段执行。

    2.png

    还是点击div3,我们将div1.addEventListener第三个参数改为true,如下可以看出div1最先执行,说明捕获阶段优先于冒泡阶段。

    3.png

    这里看完一定要敲一下,我并没有列举所有的情况,其余的情况留给你们去尝试再总结(能理解上面的就够了,真正编码不会很复杂)。

    如上就是我对事件目标查找的两种机制冒泡捕获理解。

    二、事件代理机制(事件委托)

    利用事件冒泡完成事件代理机制:

    <ul>
        <li>列表1</li>
        <li>列表2</li>
    </ul>

    当我们要给如上列表中的li都绑定一个点击事件点击获取li中的内容,一般是利用for遍历元素绑定点击事件。

    let lis = document.querySelectorAll('li');
    for (let i = 0; i < lis.length; i++) {
    	lis[i].addEventListener('click', function () {
     		console.log(this.innerHTML);
    	});
    }

    假如我们有1w个 li 节点,使用如上方式就需要绑定1w个事件,这样操非常影响代码性能。所以我们可以利用冒泡机制来解决如上的问题,就是将事件绑定到父元素身上 ul 身上。看如下代码:

    <body>
        <ul>
            <li>列表1</li>
            <li>列表2</li>
        </ul>
        <script>
            let ul = document.querySelector('ul');
            //我们可以通过事件对象(e)中的target属性可以访问到事件源(也就事件的触发元素)
            ul.addEventListener('click',function(e){
                console.log(e.target.innerHTML);
            },false);
        </script>
    </body>

    事件对象(e):无论是addEventListener绑定事件还是直接“.事件名”,事件监听的处理函数中的第一个参数为 事件对象 。事件对象包含了这个事件的详细信息,比如这个对象中包含了:事件源,事件id,事件类型,事件绑定的元素,事件触发时点击的位置等等。其中 e.target 就能访问到事件源,就是触发本次事件的源头。

    既然能给父元素绑定事件监听,又能拿到触发的源头。所以我们通过“e.target”+“冒泡机制”就可以减少事件的绑定,能提升不少的性能。

    依次点击列表1与列表2:

    4.png

    总结:通过上面代码我们知道了“事件对象”+“冒泡机制”可以实现事件委托。事件委托就是当事件触发时,通过事件冒泡(或事件捕获)把要做的事委托给父元素来处理。

    三、e.target与e.currentTarget的区别:

    四、阻止冒泡与捕获

    为什么要阻止冒泡或捕获?

    点击当前元素时以冒泡的方式传递事件如果上级元素绑定了同样的事件,就会因为冒泡传递导致触发。同样捕获的过程中,也会触发与当前元素绑定的相同事件的上级。只是触发顺序不同。

    事件代理一般使用的冒泡,当然阻止冒泡一般不会影响事件代理,因为顺序问题只会影响捕获事件,这也是为什么都使用冒泡实现事件代理机制。

    阻止冒泡或捕获的方法

    这里我不考虑兼容性问题,我相信不久将来兼容性可以得到解决。

    阻止冒泡w3c推介的方法是event.stopPropagation(),顾名思义停止传播,他是事件对象(event)的方法,此方法是阻止目标元素的继续冒泡(或捕获)

    event.stopPropagation()阻止冒泡:

    <body>
        <div id="div1">
            这是div1
            <div id="div2">
                这是div2
                <div id="div3">这是div3</div>
            </div>
        </div>
        <script>
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.onclick = function (e) {
               alert('div1');
            }
            div2.onclick = function (e) {
               e.stopPropagation();
                alert('div2');
            }
            div3.onclick = function (e) {
               alert('div3');
            }
        </script>
    </body>

    上面代码默认都是冒泡事件,我们点击div3会依次弹出’div3’与’div2’,为什么没有弹出’div1’这是因为e.stopPropagation();阻止了目标元素的事件继续冒泡到上级。如果每个点击事件都加上了e.topPropagation就不会出现多弹窗的情况。

    event.stopPropagation()阻止捕获:

    <body>
        <div id="div1">
            这是div1
            <div id="div2">
                这是div2
                <div id="div3">这是div3</div>
            </div>
        </div>
        <script>
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.addEventListener('click',function(e){
               	console.log('div1');
            },true);
            div2.addEventListener('click',function(e){
                console.log('div2');
                e.stopPropagation();
            },true);
            div3.addEventListener('click',function(e){
                console.log('div3');
            },true);
        </script>
    </body>

    当我们点击div2会依次弹出’div1’与’div2’,这也是因为在div2事件中我们设置了e.stopPropagation(),阻塞了目标元素的事件继续向下捕获。

    event.target == event.currentTarget:

    div.addEventListener('click',function(e){
    	if(event.target == event.currentTarget){
            //需要执行的代码
        }
    });

    此方法不过多解释用的不多,如果你理解了上面的内容,这个方法也能理解。

    五、补充:为什么要使用addEventListener()

    从上面代码不难看出addEventListener()有如下的优点(以下是MDN的原话):

    addEventListener() 是 W3C DOM 规范中提供的注册事件监听器的方法。它的优点包括:

    六、取消默认事件

    event.preventDefault()

    默认事件指的是<a href=""><input type="submit"> 标签这类有默认行为的标签,通过点击可以跳转或提交。我们给这类标签绑定一个点击事件,设置事件对象的preventDefault()方法就可以阻止默认事件的发生。

    <body>
       <a href="https://www.baidu.com">点击跳转</a>
        <script>
            let a = document.querySelector('a');
            addEventListener('click',function(e){
                e.preventDefault();
            })
        </script>
    </body>

    那么我们如何才能知道一个标签是否有默认事件,打印事件对象的cancelable属性,通过事件执行就可以知道e.cancelable的结果,如果为false表示有默认事件,true则没有。

    return false;

    事件执行函数中设置return false取消默认事件,但此方法不常用。

    【相关推荐:javascript学习教程

    以上就是深入了解JavaScript中的事件冒泡与捕获的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:csdn,如有侵犯,请联系admin@php.cn删除
    上一篇:一文搞懂JS中的事件冒泡机制 下一篇:分享一个Nodejs web框架:Fastify
    VIP课程(WEB全栈开发)

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• 简单聊聊JavaScript的Math对象方法• 什么是构造函数?详解JavaScript中的构造函数• JavaScript之常用事件类型整理• 一起分析JavaScript异常处理方式• 聊聊JavaScript中怎么利用Object()函数创建对象• 什么是this?深入解析JavaScript中的this
    1/1

    PHP中文网