如何根据鼠标移动角度旋转跟随鼠标的方块,解决慢速移动旋转抖动问题
问题原因
- 你当前的实现是每帧直接对比上一帧的坐标计算角度,鼠标慢速移动时,两帧之间的位移通常小于2像素,鼠标硬件采样误差、浏览器坐标取整都会导致位移方向随机波动,
Math.atan2计算出的角度就会出现大幅跳变,引发抖动。 - requestAnimationFrame的触发频率和mousemove事件触发频率不匹配,也会放大微小位移的误差。
修复方案
你可以通过最小位移阈值过滤+角度平滑插值两个优化解决抖动问题,修改后的代码如下:
修改后的JS代码
class Cursor { constructor() { this.prevX = null; this.prevY = null; this.curX = null; this.curY = null; this.angle = 0; // 初始化当前角度 this.targetAngle = 0; // 新增:目标角度 this.smoothFactor = 0.1; // 新增:平滑系数,越小越平滑,取值0-1 this.minMoveDistance = 4; // 新增:最小触发角度更新的位移阈值,单位像素 this.container = document.querySelector(".cursor"); this.follower = this.container.querySelector(".cursor-follower"); document.addEventListener("mousemove", (event) => { this.curX = event.clientX; this.curY = event.clientY; }); this.position(); } position(timestamp) { this.follower.style.top = `${this.curY}px`; this.follower.style.left = `${this.curX}px`; // 计算两帧之间的位移距离 const dx = this.curX - this.prevX; const dy = this.curY - this.prevY; const distance = Math.sqrt(dx*dx + dy*dy); // 只有位移超过阈值才更新目标角度 if (distance > this.minMoveDistance && this.prevX !== null) { this.targetAngle = Math.atan2(dy, dx) * 180/Math.PI + 90; // 处理角度环绕问题,避免从350度转到10度时转一整圈 const angleDiff = this.targetAngle - this.angle; if (angleDiff > 180) this.targetAngle -= 360; if (angleDiff < -180) this.targetAngle += 360; } // 平滑插值更新当前角度 this.angle += (this.targetAngle - this.angle) * this.smoothFactor; this.follower.style.transform = `rotateZ(${this.angle}deg)`; this.prevX = this.curX; this.prevY = this.curY; requestAnimationFrame(this.position.bind(this)); } } const cursor = new Cursor();
可调参数说明
minMoveDistance:可以根据你的需求调整,数值越大越不容易抖,但角度响应会稍慢,推荐设置为3-6像素smoothFactor:数值越小旋转越平滑,数值越大响应越快,推荐设置为0.08-0.2之间
你可以根据实际效果微调这两个参数,就能兼顾慢速移动的平滑性和快速移动的响应速度,后续要加scaleX拉伸效果也不会受影响。
内容的提问来源于stack exchange,提问作者h3ckphy
相关产品推荐
相关产品推荐

