鼠标跟随效果在Vue里怎么实现才不卡顿?
我用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>
第一个方案是用CSS动画过渡,适合简单跟随效果:
然后在CSS里给cursor加transition属性,比如
transition: transform 0.2s ease-out,这样浏览器会用GPU加速渲染。第二个方案适合复杂效果,用requestAnimationFrame做节流:
第二个方案更平滑,而且不会频繁触发Vue的响应式更新。那个0.1是缓动系数,调小点会更跟手但更费性能,自己权衡。
你每次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主题的时候我也遇到过类似问题,元素多的时候能不用响应式就别用,性能差太多了。