实现进度条从当前位置反向重置至0%的技术问题
问题:点击Reset按钮时进度条无法从当前位置反向回到0%
点击Reset按钮时,想要进度条从当前位置平滑反向滚动到0%,但现在一点Reset,进度条会先跳到100%再开始往回走,这明显不对。
修正后的完整代码
index.html
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <title>Loader Demo</title> <link rel="stylesheet" href="style.css"> <link rel="icon" type="image/png" href="favicon.png"> </head> <body> <div id="container"> <div id="loader"> <div class="bar"></div> </div> <div id="bReset"> <input type="submit" id="reset-button" name="reset-button" value="Reset"> <!-- <input type="submit" id="pause-button" name="pause-button" value="Pause"> --> <input type="submit" id="start-button" name="start-button" value="Start"> </div> </div> <script src="script.js"></script> </body> </html>
style.css
#container { display: flex; flex-direction: column; align-items: center; } #loader { width: 300px; height: 20px; border: 1px solid #ddd; border-radius: 4px; overflow: hidden; } /* 用CSS变量动态设置反向动画的起始宽度 */ @keyframes progress-reverse { from { width: var(--current-width, 100%); } to { width: 0%; } } #loader .bar { height: 100%; background-color: #007bff; animation: none; width: 0%; /* 初始化CSS变量 */ --current-width: 0%; } #reset-button { border: none; background-color: #007bff; color: white; padding: 5px 15px; font-size: 14px; border-radius: 4px; cursor: pointer; margin-top: 5px; width: 65px; } #start-button { border: none; background-color: #007bff; color: white; padding: 5px 15px; font-size: 14px; border-radius: 4px; cursor: pointer; margin-top: 5px; width: 65px; } @keyframes progress { 0% {width: 0%; background: #A1F5FF;} 100% {width: 100%; background: #007bff;} }
script.js
const sb = document.querySelector('#start-button'); const rb = document.querySelector('#reset-button'); const pBar = document.querySelector('.bar'); const loaderWidth = 300; // 和CSS里#loader的width保持一致 let isPaused = false; sb.addEventListener('click', () => { if (!isPaused) { sb.value = 'Pause'; // 清除反向动画,重置状态 pBar.style.animation = 'none'; // 强制浏览器重绘,避免动画状态冲突 void pBar.offsetWidth; pBar.style.animation = 'progress 3s linear infinite'; pBar.style.animationPlayState = 'running'; } else { sb.value = 'Start'; pBar.style.animationPlayState = 'paused'; } isPaused = !isPaused; }); rb.addEventListener('click', () => { isPaused = false; sb.value = 'Start'; // 先暂停当前的正向动画 pBar.style.animationPlayState = 'paused'; // 计算当前进度条的宽度百分比 const computedStyle = window.getComputedStyle(pBar); const barWidthPx = parseFloat(computedStyle.getPropertyValue('width')); const currentWidthPercent = (barWidthPx / loaderWidth) * 100; // 设置CSS变量,让反向动画从当前宽度开始 pBar.style.setProperty('--current-width', `${currentWidthPercent}%`); // 清除之前的动画,强制重绘,防止跳变 pBar.style.animation = 'none'; void pBar.offsetWidth; // 计算反向动画的时长:正向3秒走100%,所以按比例算时长 const reverseDuration = (currentWidthPercent / 100) * 3; // 应用反向动画,forwards让动画结束后停在0%的状态 pBar.style.animation = `progress-reverse ${reverseDuration}s linear forwards`; });
关键修复点
- 动态反向动画起点:用CSS变量
--current-width代替固定的100%起始值,让反向动画能从进度条当前的宽度开始。 - 强制重绘解决跳变:切换动画前先设
animation: none,再用void pBar.offsetWidth触发重绘,避免浏览器复用之前的动画状态导致的跳100%问题。 - 匹配反向速度:根据当前进度计算反向动画的时长,保证反向滚动的速度和正向一致。
- 状态重置:点击Reset后把Start按钮改回初始状态,避免后续操作混乱。
内容的提问来源于stack exchange,提问作者studentdev2023
相关产品推荐
相关产品推荐

