如何在动画运行时修改Element.animate()的结束关键帧?
动态调整Element.animate()关键帧实现鼠标速度条平滑过渡
核心问题分析
你当前的问题在于每次调用animate()都会创建新的动画实例,且固定设置结束帧为0px,导致动画无法跟随鼠标速度动态调整目标值。要实现平滑过渡,需要复用同一个动画实例,并在每次速度更新时动态修改其关键帧的结束值。
修复后的完整代码
HTML
<div id="mouseSpeedIndicator"></div>
CSS
div#mouseSpeedIndicator { position: fixed; bottom: 0px; left: 0px; height: 33px; background-color: green; max-width: 100vw; /* 修正为视口宽度,原100vh是视口高度,不符合需求 */ border-top-right-radius: 10px; }
JavaScript
// 修复后的鼠标速度追踪器 document.addEventListener('DOMContentLoaded', mausgeschwindigkeitVerfolgen, { once: true }); function mausgeschwindigkeitVerfolgen() { // 初始值设为0,避免NaN问题 let speedX = 0; let speedY = 0; let posX = 0; let posY = 0; let speed = 0; document.addEventListener("mousemove", function(ev){ speedX += Math.abs(ev.movementX); speedY += Math.abs(ev.movementY); speed = 10 * Math.sqrt(ev.movementX ** 2 + ev.movementY ** 2); window.mousePosition = { x: posX = ev.clientX, y: posY = ev.clientY }; }, false); setInterval(function(){ window.mouseSpeed = { x: speedX, y: speedY, t: speed }; window.mousePosition = { x: posX, y: posY }; // 重置累计速度,原代码的totalX/totalY未定义,改为speedX/speedY speedX = speedY = speed = 0; }, 100); window.mausgeschwindigkeitVerfolgen = () => ({ speed: window.mouseSpeed, pos: window.mousePosition }); return { speed: window.mouseSpeed, pos: window.mousePosition }; } // --- 动画实现代码 --- const indicator = document.querySelector('div#mouseSpeedIndicator'); let animation = null; // 初始化动画,设置初始关键帧 function initAnimation(targetWidth) { animation = indicator.animate( [{ width: '0px' }, { width: `${targetWidth}px` }], { duration: 200, easing: 'ease-out', fill: 'forwards' } ); animation.pause(); } // 动态更新动画目标值 function updateAnimation(newWidth) { if (!animation) { initAnimation(newWidth); animation.play(); return; } // 获取当前动画的进度对应的实际宽度 const currentWidth = parseFloat(getComputedStyle(indicator).width); // 暂停动画,更新关键帧 animation.pause(); animation.effect.setKeyframes([ { width: `${currentWidth}px` }, { width: `${Math.min(newWidth, window.innerWidth)}px` } // 限制最大宽度不超过视口 ]); // 重置动画进度并播放 animation.currentTime = 0; animation.play(); } // 每100ms更新一次动画目标 setInterval(() => { if (window.mouseSpeed?.t !== undefined) { updateAnimation(window.mouseSpeed.t); } }, 100);
关键实现细节
- 复用动画实例:只创建一个
Animation对象,避免每次更新都生成新动画导致的跳变。 - 动态修改关键帧:每次更新速度时,先获取元素当前的实际宽度作为动画起始帧,新的鼠标速度值作为结束帧,调用
effect.setKeyframes()更新动画。 - 状态控制:暂停动画后修改关键帧,再重置播放进度并继续播放,保证平滑过渡。
- 修复原追踪器问题:将初始变量从
NaN改为0,修正重置时未定义的变量错误,避免速度计算异常。
补充说明
- 动画时长设为200ms是为了和100ms的速度更新间隔配合,让过渡更自然,可根据需求调整。
- 添加了
Math.min(newWidth, window.innerWidth)限制最大宽度,避免超出视口范围。
内容的提问来源于stack exchange,提问作者Lampe2020
相关产品推荐
相关产品推荐

