鼠标跟随效果在Vue里怎么实现才不卡顿?

FSD-春萍 阅读 13

我用Vue写了个鼠标跟随的小圆点,但移动快了就明显掉帧,感觉很卡。是不是监听mousemove的方式不对?

下面是我现在的代码,就是直接绑在document上更新坐标:

<template>
  <div id="cursor" :style="{ left: x + 'px', top: y + 'px' }"></div>
</template>

<script>
export default {
  data() {
    return { x: 0, y: 0 }
  },
  mounted() {
    document.addEventListener('mousemove', (e) => {
      this.x = e.clientX
      this.y = e.clientY
    })
  }
}
</script>
我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
轩辕子皓
你这个写法的问题在于每次鼠标移动都会触发Vue的响应式更新,太频繁了肯定卡。我来给你两个优化方案:

第一个方案是用CSS动画过渡,适合简单跟随效果:
mounted() {
const cursor = document.getElementById('cursor')
document.addEventListener('mousemove', (e) => {
cursor.style.transform = translate(${e.clientX}px, ${e.clientY}px)
})
}

然后在CSS里给cursor加transition属性,比如transition: transform 0.2s ease-out,这样浏览器会用GPU加速渲染。

第二个方案适合复杂效果,用requestAnimationFrame做节流:
data() {
return { x: 0, y: 0, targetX: 0, targetY: 0 }
},
mounted() {
document.addEventListener('mousemove', (e) => {
this.targetX = e.clientX
this.targetY = e.clientY
if (!this.rafId) {
this.rafId = requestAnimationFrame(this.updatePosition)
}
})
},
methods: {
updatePosition() {
this.x += (this.targetX - this.x) * 0.1
this.y += (this.targetY - this.y) * 0.1
this.rafId = requestAnimationFrame(this.updatePosition)
}
},
beforeDestroy() {
cancelAnimationFrame(this.rafId)
}


第二个方案更平滑,而且不会频繁触发Vue的响应式更新。那个0.1是缓动系数,调小点会更跟手但更费性能,自己权衡。
点赞
2026-03-07 11:01
书生シ邦威
这问题跟Vue响应式更新机制有关,不是你监听方式的问题。

你每次mousemove都去改data里的x和y,Vue每次都会触发响应式更新、虚拟DOM diff、实际DOM操作。mousemove一秒触发几十次,Vue根本扛不住。

最简单的解决方案是绕过Vue的响应式,直接操作DOM。用transform代替left/top也有帮助,GPU加速嘛。

给你改过的代码:







这里有几个优化点。第一,完全不用Vue响应式,直接拿ref操作DOM。第二,用transform3d触发GPU加速,比改left/top性能好很多。第三,加了个缓动插值,鼠标移动的时候小圆点会"跟"着走而不是瞬移,视觉上更顺滑,就算掉帧也不明显。

will-change: transform 这个CSS属性也加上,浏览器会提前给它分配独立图层。

如果你想要完全跟手没有延迟感,把缓动系数0.15改成1,或者直接在mousemove里更新也行,反正不用Vue响应式就不会卡了。做WordPress主题的时候我也遇到过类似问题,元素多的时候能不用响应式就别用,性能差太多了。
点赞 1
2026-03-01 10:02