什么是 mousemove 事件?
mousemove 事件会在用户将鼠标指针移动到一个元素上时持续不断地触发,只要鼠标在元素边界内移动,哪怕只移动一个像素,这个事件就会被触发一次。

(图片来源网络,侵删)
基本语法
主要有两种方式来监听 mousemove 事件:
使用 addEventListener (推荐方式)
这是现代 JavaScript 中最标准、最灵活的方式。
// 获取要监听的元素,通常是 document 或某个具体的 DOM 元素
const element = document.body; // 或者 document.getElementById('myDiv');
// 定义一个事件处理函数(也叫监听器)
function handleMouseMove(event) {
// event 对象包含了关于事件的详细信息,比如鼠标位置
console.log("鼠标在移动!");
}
// 添加事件监听器
element.addEventListener('mousemove', handleMouseMove);
使用 onmousemove 属性 (传统方式)
这种方式比较直接,但不如 addEventListener 灵活(无法添加多个监听器)。
const element = document.body;
// 直接将一个函数赋值给 onmousemove 属性
element.onmousemove = function(event) {
console.log("鼠标在移动!");
};
核心:event 对象
当 mousemove 事件被触发时,浏览器会传递一个 event 对象给我们的处理函数,这个对象包含了非常有用的信息,其中最重要的是鼠标的坐标。

(图片来源网络,侵删)
获取鼠标位置
event 对象提供了两组坐标,它们的参考点(原点)不同:
-
clientX和clientY- 参考点:浏览器视口的左上角。
- 含义:表示鼠标指针在当前可见窗口中的位置,不考虑页面是否滚动。
- 这是最常用、最稳定的坐标。
-
pageX和pageY- 参考点:整个文档的左上角(包括被滚动隐藏的部分)。
- 含义:表示鼠标指针在整个HTML文档中的绝对位置。
- 注意:
pageX和pageY在 IE 8 及以下版本中不支持。
示例代码:

(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">MouseMove 坐标示例</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
}
#info {
background-color: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
margin-top: 20px;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>移动你的鼠标</h1>
<p>查看下方坐标的变化。</p>
<div id="info">
<p>ClientX: <span id="clientX">0</span></p>
<p>ClientY: <span id="clientY">0</span></p>
<p>PageX: <span id="pageX">0</span></p>
<p>PageY: <span id="pageY">0</span></p>
</div>
<script>
// 获取显示坐标的 span 元素
const clientXSpan = document.getElementById('clientX');
const clientYSpan = document.getElementById('clientY');
const pageXSpan = document.getElementById('pageX');
const pageYSpan = document.getElementById('pageY');
// 在整个文档上监听 mousemove 事件
document.addEventListener('mousemove', function(event) {
// 更新显示的内容
clientXSpan.textContent = event.clientX;
clientYSpan.textContent = event.clientY;
pageXSpan.textContent = event.pageX;
pageYSpan.textContent = event.pageY;
});
</script>
</body>
</html>
实战应用案例
案例1:创建一个跟随鼠标的元素
这是一个非常酷炫的效果,元素会像“小尾巴”一样跟随着鼠标。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">跟随鼠标的元素</title>
<style>
body {
height: 2000px; /* 让页面可以滚动,演示 pageY 的区别 */
cursor: none; /* 隐藏默认鼠标指针 */
}
#cursor-follower {
position: fixed; /* 关键:相对于视口定位 */
width: 20px;
height: 20px;
background-color: #007bff;
border-radius: 50%;
pointer-events: none; /* 关键:让这个元素不拦截鼠标事件 */
transform: translate(-50%, -50%); /* 让元素中心对准鼠标位置 */
transition: transform 0.1s ease-out; /* 添加平滑过渡效果 */
}
</style>
</head>
<body>
<h1>移动鼠标试试看</h1>
<p>页面很长,可以滚动一下。</p>
<div id="cursor-follower"></div>
<script>
const follower = document.getElementById('cursor-follower');
document.addEventListener('mousemove', function(event) {
// 使用 clientX 和 clientY,因为元素是 fixed 定位,相对于视口
follower.style.left = event.clientX + 'px';
follower.style.top = event.clientY + 'px';
});
</script>
</body>
</html>
案例2:简单的绘图板
我们可以利用 mousemove 事件,结合 canvas 元素来创建一个简单的绘图工具。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">简单绘图板</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="drawingCanvas" width="800" height="400"></canvas>
<p>按住鼠标左键并拖动来绘画。</p>
<script>
const canvas = document.getElementById('drawingCanvas');
const ctx = canvas.getContext('2d');
// 设置画笔样式
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.strokeStyle = 'blue';
let isDrawing = false;
let lastX = 0;
let lastY = 0;
function startDrawing(e) {
isDrawing = true;
// 获取鼠标在 canvas 内的坐标
const rect = canvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
}
function draw(e) {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
// 开始一条新路径
ctx.beginPath();
// 移动到上一个点
ctx.moveTo(lastX, lastY);
// 画线到当前点
ctx.lineTo(currentX, currentY);
// 描边
ctx.stroke();
// 更新上一个点的坐标
lastX = currentX;
lastY = currentY;
}
function stopDrawing() {
isDrawing = false;
}
// 添加事件监听器
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing); // 当鼠标离开 canvas 时也停止绘画
</script>
</body>
</html>
性能优化与最佳实践
mousemove 事件触发非常频繁,如果处理不当,可能会导致严重的性能问题(页面卡顿),必须进行优化。
使用 throttle (节流)
节流函数确保一个函数在指定的时间间隔内最多只执行一次,这对于 mousemove 来说至关重要,因为它可以将事件处理的频率从每秒数百次降低到每秒几十次。
手写一个简单的 throttle 函数:
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 使用 throttle 包装你的处理函数
const expensiveFunction = function(e) {
console.log(`处理鼠标位置: ${e.clientX}, ${e.clientY}`);
};
const throttledHandler = throttle(expensiveFunction, 100); // 每 100ms 最多执行一次
document.addEventListener('mousemove', throttledHandler);
使用 requestAnimationFrame
requestAnimationFrame 是浏览器提供的 API,用于在下一次重绘之前调用指定的回调函数,它与浏览器的刷新率同步(通常是 60fps),是做动画和视觉效果的最佳选择。
let isRunning = false;
function handleMouseMove(event) {
// 如果已经在运行,则不再请求新的动画帧
if (isRunning) return;
isRunning = true;
requestAnimationFrame(function() {
// 在这里执行你的耗时代码
console.log(`RAF 处理鼠标位置: ${event.clientX}, ${event.clientY}`);
// 执行完毕后,重置标志
isRunning = false;
});
}
document.addEventListener('mousemove', handleMouseMove);
移除事件监听器
当代码不再需要监听事件时(比如组件卸载、页面切换),一定要记得移除事件监听器,以避免内存泄漏。
function handleMouseMove(event) {
// ... 处理逻辑
}
// 添加监听
document.addEventListener('mousemove', handleMouseMove);
// ... 在某个时刻,不再需要监听了
// 移除监听 (注意:这里必须是同一个函数引用)
document.removeEventListener('mousemove', handleMouseMove);
| 特性 | 描述 |
|---|---|
| 触发时机 | 鼠标在元素上持续移动时。 |
| 关键对象 | event 对象,包含 clientX, clientY, pageX, pageY 等坐标信息。 |
| 核心用途 | 跟踪鼠标位置、创建交互效果(如悬停提示、跟随动画)、实现绘图功能。 |
| 性能关键 | 必须进行节流 (throttle) 或使用 requestAnimationFrame,否则极易导致性能问题。 |
| 最佳实践 | 优先使用 addEventListener,并在不需要时用 removeEventListener 清理。 |
掌握 mousemove 事件是前端交互开发的基础,希望这份教程能帮助你理解并熟练使用它!
