Web前端入门第 76 问:JavaScript 鼠标事件(mouse) enter/leave 和 over/out 区别
<h3 id="题外话">题外话</h3><p>在考察事件基础的时候,会经常被问及 <code>click</code>、<code>mousedown</code>、<code>mouseup</code> 它们三者执行的先后顺序是怎样的?</p>
<p>如果平时没太注意,这细节可能就会忽略,毕竟很少会在同一个元素上面同时绑定这三个事件~~</p>
<p>直接上示例:</p>
<pre><code class="language-html"><div class="c">测试点击事件</div>
<script>
(() => {
const c = document.querySelector('.c')
c.addEventListener('click', () => {
console.log('click')
})
c.addEventListener('mousedown', () => {
console.log('mousedown')
})
c.addEventListener('mouseup', () => {
console.log('mouseup')
})
})()
</script>
</code></pre>
<p>实际控制台输出:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202507/596097-20250708114312141-1176767272.png"></p>
<p>而且 click 事件鼠标在元素上点击之后,再按住鼠标移开元素,此时并不会触发 click 事件,仅 <code>mousedown</code> 事件被触发了。<br>
这里就有一个比较有意思的操作了,如果开发中想要用户无法取消事件,那就直接用 <code>mousedown</code> 事件吧~~</p>
<h2 id="事件-enterleave-和-overout-区别">事件 enter/leave 和 over/out 区别</h2>
<p>这两组事件都是鼠标进入元素和离开元素时触发,用文字描述的区别就是 over/out 这一组事件会冒泡,而 enter/leave 这组事件不会冒泡。</p>
<p>如果绑定事件没有子元素,其实两者没有任何区别,比如:</p>
<pre><code class="language-html"><style>
.c {
border: 1px solid #000;
padding: 8px;
}
</style>
<div class="c">前端路引--事件测试</div>
<script>
(() => {
const c = document.querySelector('.c')
c.addEventListener('mouseover', () => {
console.log('mouseover')
})
c.addEventListener('mouseout', () => {
console.log('mouseout')
})
c.addEventListener('mouseenter', () => {
console.log('mouseenter')
})
c.addEventListener('mouseleave', () => {
console.log('mouseleave')
})
})()
</script>
</code></pre>
<p>效果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202507/596097-20250708114319958-1303132452.gif"></p>
<p>可以明显看到,这两组事件触发都是一样的,在鼠标移入和移除的时候都触发了。</p>
<p>但这里有一个细节:<strong>enter/leave 这组事件永远都是在 over/out 后面触发,不论代码的先后顺序,也不论是否是事件捕获!!</strong></p>
<h3 id="存在子元素时">存在子元素时</h3>
<p>上面事件看不出区别来,别急,来一个包含子元素的例子:</p>
<pre><code class="language-html"><style>
.bd {
border: 1px solid #000;
padding: 8px;
}
</style>
<div id="container1" class="bd">
外层
<div class="bd">
内层
<div class="bd">
最内层
<div class="bd">
按钮
</div>
</div>
</div>
</div>
<script>
(() => {
const c = document.querySelector('#container1')
c.addEventListener('mouseover', () => {
console.log('mouseover')
})
c.addEventListener('mouseout', () => {
console.log('mouseout')
})
c.addEventListener('mouseenter', () => {
console.log('mouseenter')
})
c.addEventListener('mouseleave', () => {
console.log('mouseleave')
})
})()
</script>
</code></pre>
<p>效果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202507/596097-20250708114325858-1540951934.gif"></p>
<p>可以看到 over/out 这组事件,在鼠标每次进入子元素时候,都会触发父元素的 over/out 事件;而 enter/leave 这组事件只会在进入/离开父元素时候触发一次。</p>
<p>前面说了,over/out 是冒泡事件,那能不能通过 event.stopPropagation() 来阻止冒泡?</p>
<p>把所有事件都添加上 <code>阻止传播</code> 试试:</p>
<pre><code class="language-js">(() => {
const c = document.querySelector('#container1')
c.addEventListener('mouseover', (event) => {
event.stopPropagation()
console.log('mouseover')
})
c.addEventListener('mouseout', (event) => {
event.stopPropagation()
console.log('mouseout')
})
c.addEventListener('mouseenter', (event) => {
event.stopPropagation()
console.log('mouseenter')
})
c.addEventListener('mouseleave', (event) => {
event.stopPropagation()
console.log('mouseleave')
})
document.querySelectorAll('.bd').forEach((item) => {
item.addEventListener('mouseover', (event) => {
event.stopPropagation()
})
item.addEventListener('mouseout', (event) => {
event.stopPropagation()
})
})
})()
</code></pre>
<p>效果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202507/596097-20250708114331550-202178292.gif"></p>
<p>可以看到虽然 <code>最内层</code> 里面的元素移动不会触发顶层事件,但在 <code>内层</code> 和 <code>外层</code> 来回移动的时候,还是会触发事件冒泡。</p>
<p>可以理解为每个子元素都有物理空间,over/out 这组事件在父元素和子元素的物理空间来回移动的时候,还是会触发 <code>over/out</code> 事件。</p>
<h2 id="写在最后">写在最后</h2>
<p>开发中需要根据需求选择合适的事件,一般情况 enter/leave 这组事件使用率相对而言较高一些。</p>
</div>
<div id="MySignature" role="contentinfo">
<p> </p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18972694</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/linx/p/18972694
頁:
[1]