应使用 transform + mousemove 实现图片跟随,因其性能优、无重排、定位准;需配合 requestAnimationFrame 节流、绝对定位、clientX/Y 坐标、移动端 touchmove 兼容及滚动补偿等细节。

直接用 transform + mousemove,别碰 left/top 和 background-position
性能差、掉帧、坐标错位——这三个问题全出在用错了更新方式。浏览器对 transform 的合成层优化是成熟的,而 left/top 触发重排,background-position 在滚动或缩放时偏移失准。实测中,同一设备上 transform: translate() 的 CPU 占用不到 background-position 的三分之一。
- 图片必须设
position: absolute或fixed,否则transform无法脱离文档流精准定位 - 监听目标选
document最稳妥;若限定区域,就监听容器并用getBoundingClientRect()算相对坐标 - 永远用
e.clientX/e.clientY,不是e.pageX/e.pageY——后者含滚动偏移,鼠标一滚图片就飞出视口 - 加
pointer-events: none到跟随图上,否则它会挡住下层按钮、链接的点击
requestAnimationFrame 不是可选项,是必选项
原生 mousemove 每秒触发上百次,直接在里面改样式等于让渲染引擎排队等你,结果就是拖影、跳变、跟不上指针。用 requestAnimationFrame 不是为了“更酷”,而是让更新节奏对齐屏幕刷新率(60fps),且天然节流。
- 只在事件里存坐标:
lastX = e.clientX; lastY = e.clientY;,不操作 DOM - 用标志位(如
pending)防止重复进队列 - 在
requestAnimationFrame回调里读取最新坐标,一次性执行img.style.transform = `translate(${lastX}px, ${lastY}px)` - 别忘了移动端:iOS Safari 完全不触发
mousemove,必须同时监听touchmove并取e.touches[0].clientX
移动端 touchmove 的三个硬坑
写完 PC 端一跑就动,扔到手机上完全没反应——这不是代码错,是平台差异没填平。
-
touchmove默认会触发页面滚动,必须加e.preventDefault(),但只对目标元素生效,别漏掉 -
e.changedTouches在手指刚落时可能为空,要用e.touches[0]取第一个触点 - 加
touch-action: none到目标元素上,否则双指缩放、滑动等系统手势会干扰跟随逻辑 - 如果只希望单指生效,检查
e.touches.length === 1再更新坐标,避免多指乱动
为什么鼠标离开后图片还在动?
常见于监听了 document 却没清理状态,或者 mouseleave 绑在错误容器上。更隐蔽的问题是:滚动时 clientX/clientY 值不变,但视觉位置已偏移,导致图片“悬停”在旧位置。
立即学习“前端免费学习笔记(深入)”;
- 监听
document时,mouseleave事件根本不会触发——得靠mouseout或手动检测是否移出视口 - 若用容器监听,确保容器有明确宽高且
overflow: visible,否则mouseleave可能被子元素遮挡拦截 - 滚动场景下,要么把跟随逻辑和
scroll耦合(读window.scrollX/Y补偿),要么干脆限制为“仅视口内跟随” - 最保险的做法:鼠标移出时设
transform: translate(0, 0),而不是依赖事件自动复位



















