由mouseover和mouseenter引发的思考

mouseover和mouseenter

这是两个都是鼠标移入事件,首先要明确的是mouseover可以冒泡,而mouoseenter无法冒泡,这是它们的最根本区别

示例说明

这两者间的区别可以明显体现在父子元素间

示例代码:


<!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>mouseover与mouseenter的区别</title>

    <style>

        body {

            margin: 0;

            padding: 0;

        }

        .parent-over,

        .parent-enter {

            float: left;

            width: 200px;

            height: 200px;

            background-color: pink;

            margin-left: 10px;

        }

        .son-over,

        .son-enter {

            width: 50px;

            height: 50px;

            background-color: blue;

            margin: 0 auto;

            color: white;

        }

    </style>

</head>

<body>

    <div class="parent-over">

        mouserover

        <div class="son-over">son</div>

    </div>

    <div class="parent-enter">

        mouseenter

        <div class="son-enter">son</div>

    </div>

    <script>

        var over = document.querySelector(".parent-over");

        var enter = document.querySelector(".parent-enter");

        over.addEventListener("mouseover", function() {

            console.log("mouseover");

        });

        enter.addEventListener("mouseenter", function() {

            console.log("mouseenter");

        });

    </script>

</body>

</html>

通过以上代码构造两对父子元素,一个父亲元素绑定mouseover,另一个父亲元素绑定mouseenter

虽然mouseovermouseenter都是鼠标移入事件,但当鼠标在父子元素间移动时,左侧和右侧的鼠标移入事件触发的结果是不同的

当鼠标进入左侧粉色背景的父级元素时,会触发绑定在父元素的鼠标移入事件,当鼠标继续移动进入蓝色背景的子元素时,左侧的子元素会触发再次触发该事件,从左侧子元素移动回粉色区域时,父元素又会触发一次该事件

而当鼠标进入右侧粉色背景的父级元素时,会触发绑定在父元素的鼠标移入事件,但只要鼠标不离开右侧粉色区域,鼠标无论如何在父子元素间移动,都不会再触发该事件(除非鼠标离开右侧粉色区域后再进入)

查看控制台打印的信息,左侧的mouseover被触发了3次,右侧被触发了1次

这两者的区别就是由**mouseover可以冒泡,而mouoseenter无法冒泡**导致的:

对于左侧:当鼠标第一次进入父元素时,自然会触发鼠标移入事件,执行一次事件处理函数,这是第1次;当鼠标继续移动进入子元素时,此时并没有在子元素绑定mouseover的事件处理函数,但由于mouseout会冒泡,因此向上冒泡到父元素时会触发绑定了处理函数的mouseout,这是第2次;当鼠标从子元素移动到父元素时,会再次触发该事件,因为此时认为是从父元素外的区域“进入”,这是第3次,所以共有3次

对于右侧:当鼠标第一次进入父元素时,自然会触发鼠标移入事件,执行一次事件处理函数,这是第1次;当鼠标移入子元素时,并不能触发事件,因为mouseenter不冒泡,因此不能触发父元素的mouseenter事件;当鼠标从子元素移动到父元素时,也不会触发事件,因为此时依然看作是在父元素中来回移动而已,所以只有1次

对于这两个鼠标移入事件,有两个对应的鼠标移出事件:

mouseover对应于mouseout

mouseenter对应于mouseleave

mouseoutmouseleave的根本区别在于前者可以冒泡,而后者不能,这点和两个鼠标移入事件类似

为什么要同时有两种鼠标移入(两种鼠标移出)事件?

这里给出我个人的思考

首先要知道mouseenter是在捕获阶段过程中执行事件处理函数的,而不能在冒泡阶段过程中进行;mouseout是可以在捕获阶段和冒泡阶段选择一个阶段来执行事件处理函数的(默认为冒泡阶段)

我们可以阻断冒泡(stoppropagation()),而捕获是不可阻断的(当有事件被触发时,事件流的传播是从DOM树的最顶层的document向下传播寻找事件源的,当找到了事件源就会停止向下传播,而捕获的方向就是这个方向)

当父元素和子元素都要绑定鼠标移入事件时

mouseenter是只有捕获阶段,所以事件处理函数的执行是在捕获阶段过程中进行的。假如子元素的mouseenter事件被触发了,事件流必然会经过其父元素,父元素绑定了mouseenter事件,那么就必然会触发父元素的mouseenter事件并执行对应的事件处理函数,然后再执行子元素上的事件处理函数。捕获阶段是不可阻断的,所以这是不可避免的。有时我们只希望触发子元素的事件,这时就需要利用mouseover

mouseover可以冒泡,当父子元素都绑定了mouseover,如果希望触发子元素时不触发父元素,那么只需要利用stoppropagetion()阻止冒泡即可,这就可以实现mouseenter不能实现的(算是弥补mouseenter的“缺陷”)

当只有父元素绑定鼠标移入事件,而子元素不绑定时

mouseover默认是在冒泡过程中执行事件处理函数,而由于事件可以冒泡,当子元素的事件被触发后,也会触发父元素的事件,而这时子元素并没有绑定任何相关事件,这需要特地去为子元素使用阻止冒泡的操作(如下),否则当鼠标移入子元素时会触发一次父元素绑定的事件。但使用mouseenter是更加简练的方式


// 阻止子元素冒泡

son.addListener("mouseover", function(e) {

    e.stoppropagation();

});

mouseenter不能冒泡,那么直接应用mouseenter则只会触发父元素,当鼠标进入子元素时,也不会再次触发父元素

当只有子元素绑定鼠标移入事件,而父元素不绑定时

使用哪个效果都一样

综上,当父子元素都绑定了鼠标移入事件,如果希望总是独立地分别触发父元素和子元素的鼠标移入事件,那么只有mouseoverstoppropagation()配合使用才能实现;而当父元素绑定了鼠标移入事件,而子元素没有绑定,那么直接使用mouseenter将会更简练

另外,由于mouseover实际上都可以应用到以上前两种情况中,而mouseenter无法处理第一种情况,mouseenter看起来“比较没有必要存在”

(对于mouseoutmouseleave的分析类似以上)

引发的关于click的思考

clickmouseenter相反,click只能在冒泡阶段过程中执行事件处理函数,而不能在捕获阶段过程中。这又是为什么呢?以下给出我的个人见解

对于点击事件,我们希望的是一种“精准的点击效果”,也就是当我们点击了一个元素,我们往往希望的是只触发绑定在这个元素上的点击事件,而不触发其他元素的点击事件(往往是父元素的)。对于父子元素都绑定了点击事件的情况来说,只需要阻止子元素的点击事件冒泡即可。那如果click可以在捕获阶段过程中执行事件处理函数应该也不影响吧?接下来我假设可以

我们知道,大多数事件都可以选择在两个阶段中的一个执行事件处理函数,默认都是在冒泡阶段。可以通过将addEventListener()capture参数设置为true实现在捕获阶段执行处理函数,那么如果将click设置在捕获阶段执行事件处理函数,其父元素如果有点击事件的话,那么总是在子元素点击事件处理函数执行前执行父元素的执行函数。对于点击效果来说,应该是“点哪从哪开始触发”,捕获阶段的效果显然是,“点哪随便从哪触发”,这时如果祖先元素也有点击事件,整个点击效果将会十分不符合预期,本来需要的点击效果却在最后才出现(或许由于其他点击事件的作用根本无法出现)

由此可见,click根本没有在捕获阶段执行事件处理函数的需要

javascript
64 views
Comments
登录后评论
Sign In
·

感谢分享 学习了