关于mouseenter和mouseover的冒泡阶段和捕获阶段相关问题的大汇总

关于mouseenter和mouseover的冒泡阶段和捕获阶段相关问题的大汇总

写在前面,这里是对mouseenter、mouseleave、mouseover、mouseout四个事件的原理做一个总结,方便大家在检索问题的时候,能够看到,给大家提供一个理解的思路;当然也希望老师可以看一下,如果我的理解哪里有问题,还请指出


原理总结

1、冒泡阶段执行顺序由内向外;捕获阶段执行顺序有外向内

2、mouseenter和mouseleave冒泡阶段是不冒泡的,简单来说就是,子元素触发事件的时候不会引起父元素的事件监听;而mouseover和mouseout是可以冒泡的

3、四个事件的捕获阶段都是可以捕获的;所以,如果是监听捕获阶段的mouseenter的话,当子元素触发事件的时候会引起父元素的事件监听

4、mouseenter和mouseleave需要把盒模型想成是立体的,表面上来看,子元素占据了父元素的一些区域,但从结构上来看的话,子元素依然还在父元素的区域内;mouseover和mouseout需要把盒模型想成是平面的,子元素占据了父元素的区域后就不再算是父元素区域了


举例说明

https://img1.sycdn.imooc.com//climg/639c7089092891f407740618.jpg

  • 监听鼠标从A区域(子元素)移动到B区域(A的父元素、C的子元素)的冒泡阶段

对于mouseleave来说,因为不会冒泡,所以只能触发A区域的离开事件,并不会触发B、C区域的离开事件;

对于mouseenter来说,想象成是立体的空间,所以不会触发B区域的进入事件;

对于mouseout来说,因为有冒泡机制,所以触发A区域的离开事件同时,也会触发B、C区域的离开事件,由内向外依次执行;

对于mouseover来说,想象成是一个平面,所以会触发B区域的进入事件,同时由于冒泡机制也会触发C区域的进入事件,由内向外依次执行;

  • 监听鼠标从A区域(子元素)移动到B区域(A的父元素、C的子元素)的捕获阶段

对于mouseleave来说,因为有捕获机制,所以触发A区域的离开事件同时,也会触发B、C区域的离开事件;由外向内依次执行;

对于mouseenter来说,想象成是立体的空间,所以不会触发B区域的进入事件;

对于mouseout来说,因为有捕获机制,所以触发A区域的离开事件同时,也会触发B、C区域的离开事件;由外向内依次执行;

对于mouseover来说,想象成是一个平面,所以会触发B区域的进入事件,同时由于捕获机制也会触发C区域的进入事件,由外向内依次执行;


以下是我作各种尝试时的代码,方便大家做测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box1{
            width: 400px;
            padding: 100px;
            padding-bottom: 0;
            background-color: yellow;
            /* 解决margin的传递问题,也是为了验证鼠标移动到margin部分也算是离开 */
            border: 1px solid #000;
        }
        #box2{
            width: 200px;
            height: 200px;
            padding: 100px;
            background-color: yellowgreen;
            margin-bottom: 100px;
        }
        #box3{
            width: 200px;
            height: 200px;
            background-color: aqua;
        }
    </style>
</head>
<body>
    <div id="box1">
        <div id="box2">
            <div id="box3">
            </div>
        </div>
    </div>
    <script>
        var box1 = document.getElementById('box1');
        var box2 = document.getElementById('box2');
        var box3 = document.getElementById('box3');

        // box1.addEventListener('mouseleave',function(){
        //     console.log('移出1');
        // },true)
        // box2.addEventListener('mouseleave',function(){
        //     console.log('移出2');
        // },true)
        // box3.addEventListener('mouseleave',function(){
        //     console.log('移出3');
        // },true)

        // box1.addEventListener('mouseleave',function(){
        //     console.log('移出1');
        // },false)
        // box2.addEventListener('mouseleave',function(){
        //     console.log('移出2');
        // },false)
        // box3.addEventListener('mouseleave',function(){
        //     console.log('移出3');
        // },false)

        // box1.addEventListener('mouseout',function(){
        //     console.log('移出1');
        // },true)
        // box2.addEventListener('mouseout',function(){
        //     console.log('移出2');
        // },true)
        // box3.addEventListener('mouseout',function(){
        //     console.log('移出3');
        // },true)

        // box1.addEventListener('mouseout',function(){
        //     console.log('移出1');
        // },false)
        // box2.addEventListener('mouseout',function(){
        //     console.log('移出2');
        // },false)
        // box3.addEventListener('mouseout',function(){
        //     console.log('移出3');
        // },false)

        // box1.addEventListener('mouseover',function(){
        //     console.log('移入1');
        // },true)
        // box2.addEventListener('mouseover',function(){
        //     console.log('移入2');
        // },true)
        // box3.addEventListener('mouseover',function(){
        //     console.log('移入3');
        // },true)

        // box1.addEventListener('mouseenter',function(){
        //     console.log('移入1');
        // },true)
        // box2.addEventListener('mouseenter',function(){
        //     console.log('移入2');
        // },true)
        // box3.addEventListener('mouseenter',function(){
        //     console.log('移入3');
        // },true)

    </script>
</body>
</html>

写在最后,起因是当我在尝试事件委托时,我发现如果我去监听mouseenter的捕获阶段,也能实现委托,然后就去做各种尝试,继而跳出了更多的问题,最后总结出了这样一套原理。有了这些原理之后,对于事件委托的理解也就更深刻了,也知道了为什么mouseenter的捕获阶段能实现事件委托。

希望对大家有帮助!

正在回答

登陆购买课程后可参与讨论,去登陆

1回答

同学你好,按照同学的思路去理解,老师个人是认同的。很棒!继续努力,祝学习愉快!

  • 今年刚满10周岁 提问者 #1

    谢谢老师!我还在想,mouseenter天生不冒泡是不是也可以想成它是不能进行事件传播的;然后就是只要事件能传播,其实都可以进行事件委托,这两个理解对不对?

    2022-12-17 10:20:26
  • 1、理解的对,它本身是被官方定义为就没有冒泡机制的。

    https://developer.mozilla.org/zh-CN/docs/Web/API/Element/mouseenter_event 

    2、事件传播确实可以进行事件委托,但是要注意它们的特性比如说我们使用mouseenter时,父级与子级都有mouseenter,那么在触发子级的时候也会触发父级的mouseenter,因为捕获阶段是没办法禁止的,所以使用mouseenter就不合适了,需要使用mouseover然后并将冒泡阻止才行。

    祝学习愉快!

    2022-12-17 10:28:35
  • 了然,谢谢!

    2022-12-17 10:34:41
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师