为什么 mousemove 事件在元素外还会触发?

端木广红 阅读 13

我给一个 div 绑定了 mousemove 事件,但鼠标移出这个 div 后事件还在不断触发,这不应该啊?不是只有在元素内部才会触发吗?

我试过用 event.target 检查,发现有时候 target 是子元素,但即使完全移出容器区域,mousemove 还是会进来。是不是我哪里理解错了?

<div id="box" style="width: 200px; height: 200px; background: lightblue;">
  <span>Move me</span>
</div>

<script>
  document.getElementById('box').addEventListener('mousemove', (e) => {
    console.log('moving', e.clientX, e.clientY);
  });
</script>
我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
a'ゞ康平
mousemove是监听整个文档的,要用mouseenter/mouseleave替代。或者加个边界检查:

document.getElementById('box').addEventListener('mousemove', (e) => {
const rect = e.currentTarget.getBoundingClientRect();
if (e.clientX >= rect.left && e.clientX <= rect.right &&
e.clientY >= rect.top && e.clientY <= rect.bottom) {
console.log('moving', e.clientX, e.clientY);
}
});
点赞 3
2026-03-06 17:04
Air-蕴轩
这个问题其实涉及到事件冒泡机制。你遇到的这个现象很正常,但确实容易让人困惑。具体来说:

mousemove事件会在鼠标移动时持续触发,而且它会冒泡到父元素。也就是说,即使鼠标已经移出了你的
,但只要还在子元素上移动,事件就会冒泡到父元素div。

要解决这个问题,我们需要检查事件的实际触发位置。event.target是实际触发事件的元素,而event.currentTarget才是绑定事件的元素。我们可以这样修改代码:

document.getElementById('box').addEventListener('mousemove', (e) => {
// 只有当鼠标确实在box元素上时才触发
if (e.target === e.currentTarget) {
console.log('moving', e.clientX, e.clientY);
}
});


不过这样只能解决子元素的问题,如果鼠标完全移出整个元素区域还会触发,那可能是浏览器的事件处理机制导致的。更保险的做法是用mouseenter和mouseleave配合:

let isInside = false;
const box = document.getElementById('box');

box.addEventListener('mouseenter', () => {
isInside = true;
});

box.addEventListener('mouseleave', () => {
isInside = false;
});

box.addEventListener('mousemove', (e) => {
if (isInside) {
console.log('moving', e.clientX, e.clientY);
}
});


之所以会出现这个现象,是因为浏览器的事件系统设计就是这样的。mousemove事件本质上是全局的,只是我们通常把它绑定在特定元素上而已。当鼠标移动时,浏览器会持续发送这些事件,直到你明确告诉它停止。

我之前也被这个坑过,调试了半天才发现是事件冒泡在作怪。现在遇到这种需求都会直接用mouseenter/mouseleave来划清边界,这样逻辑更清晰。
点赞 2
2026-03-05 13:12