【问题标题】:How to make animated progress bar continuous?如何使动画进度条连续?
【发布时间】:2022-01-15 10:49:09
【问题描述】:

我有一个与倒计时相关的动画进度条。

目前进度条的动画是离散的

如何在不改变代码中其他逻辑的情况下使其连续

另外,是否可以使用requestAnimationFrame(就像动画进度条的创建方式)而不是当前的setInterval 创建计时器?

var timer = null;
var progress_bar = null;
var timePassed;
var TIME_LIMIT;
var timeLeft;


function startTimerAndProgressbar() {
    timePassed = 0;
    TIME_LIMIT = 10;
    timeLeft = TIME_LIMIT;
    
    startTimer();
    id("progress-bar").style.visibility = "visible";
    progress_bar = requestAnimationFrame(updateProgressBar);
}

function pauseTimerAndProgressbar() {
    clearInterval(timer);
    pauseProgressBar();
    id("pause-btn").disabled = true;
    id("resume-btn").disabled = false;
}

function resumeTimerAndProgressbar() {
    startTimer();
    resumeProgressBar();
    id("pause-btn").disabled = false;
    id("resume-btn").disabled = true;
}


/* HELPER FUNCTION */
function id(id) {
    return document.getElementById(id);
}


/* PROGRESS BAR */
function updateProgressBar() {
    var timeFraction = timeLeft / TIME_LIMIT;
    id("progress-bar-inner").style.width = timeFraction * 100 + "%";
    progress_bar = requestAnimationFrame(updateProgressBar);
    if (id("progress-bar-inner").style.width <= 0) {
        pauseProgressBar();
    }
}

function pauseProgressBar() {
    cancelAnimationFrame(progress_bar);
}

function resumeProgressBar() {
    progress_bar = requestAnimationFrame(updateProgressBar);
}


/* TIMER */
function startTimer() {
    id("timer").textContent = formatTime(timeLeft);
    timer = setInterval(function() {
        timePassed = timePassed += 1;
        timeLeft = TIME_LIMIT - timePassed;
        id("timer").textContent = formatTime(timeLeft);
        if (timeLeft == 0) { clearInterval(timer); }
    }, 1000);
}

function formatTime(time) {
    var m = Math.floor(time / 60);
    var s = time % 60;
    m = (m < 10) ? ("0" + m) : m;
    s = (s < 10) ? ("0" + s) : s;
    return `${m}:${s}`;
}
#timer {
    font-size: 25px;
    font-weight: bold;
}

#progress-bar {
    visibility: hidden;
    width: 100%;
    margin: 25px auto;
    border: solid 1px #000;
    border-radius: 10px;
}

#progress-bar-inner {
    height: 15px;
    border-radius: 10px;
    width: 100%;
    background-color: orange;
}
<p id="timer"></p>
<div id="progress-bar">
    <div id="progress-bar-inner"></div>
</div>

<br>
<button onclick="startTimerAndProgressbar()" id="start-btn">Start</button>
<button onclick="pauseTimerAndProgressbar()" id="pause-btn">Pause</button>
<button onclick="resumeTimerAndProgressbar()" id="resume-btn" disabled>Resume</button>

【问题讨论】:

  • 无需更改代码中的其他逻辑,但您的代码并不完美,尤其是在一个接一个地多次单击开始时。

标签: javascript html css


【解决方案1】:

transition: width 1s; 添加到您的#progress-bar-inner

var timer = null;
var progress_bar = null;
var timePassed;
var TIME_LIMIT;
var timeLeft;


function startTimerAndProgressbar() {
    timePassed = 0;
    TIME_LIMIT = 10;
    timeLeft = TIME_LIMIT;
    
    startTimer();
    id("progress-bar").style.visibility = "visible";
    progress_bar = requestAnimationFrame(updateProgressBar);
}

function pauseTimerAndProgressbar() {
    clearInterval(timer);
    pauseProgressBar();
    id("pause-btn").disabled = true;
    id("resume-btn").disabled = false;
}

function resumeTimerAndProgressbar() {
    startTimer();
    resumeProgressBar();
    id("pause-btn").disabled = false;
    id("resume-btn").disabled = true;
}


/* HELPER FUNCTION */
function id(id) {
    return document.getElementById(id);
}


/* PROGRESS BAR */
function updateProgressBar() {
    var timeFraction = timeLeft / TIME_LIMIT;
    id("progress-bar-inner").style.width = timeFraction * 100 + "%";
    progress_bar = requestAnimationFrame(updateProgressBar);
    if (id("progress-bar-inner").style.width <= 0) {
        pauseProgressBar();
    }
}

function pauseProgressBar() {
    cancelAnimationFrame(progress_bar);
}

function resumeProgressBar() {
    progress_bar = requestAnimationFrame(updateProgressBar);
}


/* TIMER */
function startTimer() {
    id("timer").textContent = formatTime(timeLeft);
    timer = setInterval(function() {
        timePassed = timePassed += 1;
        timeLeft = TIME_LIMIT - timePassed;
        id("timer").textContent = formatTime(timeLeft);
        if (timeLeft == 0) { clearInterval(timer); }
    }, 1000);
}

function formatTime(time) {
    var m = Math.floor(time / 60);
    var s = time % 60;
    m = (m < 10) ? ("0" + m) : m;
    s = (s < 10) ? ("0" + s) : s;
    return `${m}:${s}`;
}
#timer {
    font-size: 25px;
    font-weight: bold;
}

#progress-bar {
    visibility: hidden;
    width: 100%;
    margin: 25px auto;
    border: solid 1px #000;
    border-radius: 10px;
}

#progress-bar-inner {
    height: 15px;
    border-radius: 10px;
    width: 100%;
    background-color: orange;
    transition: width 1s;
}
<p id="timer"></p>
<div id="progress-bar">
    <div id="progress-bar-inner"></div>
</div>

<br>
<button onclick="startTimerAndProgressbar()" id="start-btn">Start</button>
<button onclick="pauseTimerAndProgressbar()" id="pause-btn">Pause</button>
<button onclick="resumeTimerAndProgressbar()" id="resume-btn" disabled>Resume</button>

【讨论】:

  • 谢谢!但这似乎仍然不理想,因为动画速度不一致。如何让它完美平滑(和连续)?
【解决方案2】:

您的 timer setInterval 函数在几秒钟内运行。您需要更改间隔,因此更改TIMELIMIT 的值以匹配。

var timer = null;
var progress_bar = null;
var timePassed;
var TIME_LIMIT;
var timeLeft;


function startTimerAndProgressbar() {
    timePassed = 0;
    TIME_LIMIT = 10;
    timeLeft = TIME_LIMIT*100;
    
    startTimer();
    id("progress-bar").style.visibility = "visible";
    progress_bar = requestAnimationFrame(updateProgressBar);
}

function pauseTimerAndProgressbar() {
    clearInterval(timer);
    pauseProgressBar();
    id("pause-btn").disabled = true;
    id("resume-btn").disabled = false;
}

function resumeTimerAndProgressbar() {
    startTimer();
    resumeProgressBar();
    id("pause-btn").disabled = false;
    id("resume-btn").disabled = true;
}


/* HELPER FUNCTION */
function id(id) {
    return document.getElementById(id);
}


/* PROGRESS BAR */
function updateProgressBar() {
    var timeFraction = timeLeft / (TIME_LIMIT*100);
    id("progress-bar-inner").style.width = timeFraction * 100 + "%";
    progress_bar = requestAnimationFrame(updateProgressBar);
    if (id("progress-bar-inner").style.width <= 0) {
        pauseProgressBar();
    }
}

function pauseProgressBar() {
    cancelAnimationFrame(progress_bar);
}

function resumeProgressBar() {
    progress_bar = requestAnimationFrame(updateProgressBar);
}


/* TIMER */
function startTimer() {
    id("timer").textContent = formatTime(timeLeft);
    timer = setInterval(function() {
        timePassed += 1;
        timeLeft = TIME_LIMIT*100 - timePassed;
        id("timer").textContent = formatTime(Math.ceil(timeLeft/100));
        if (timeLeft == 0) { clearInterval(timer); }
    }, 10);
}

function formatTime(time) {
    var m = Math.floor(time / 60);
    var s = time % 60;
    m = (m < 10) ? ("0" + m) : m;
    s = (s < 10) ? ("0" + s) : s;
    return `${m}:${s}`;
}
#timer {
    font-size: 25px;
    font-weight: bold;
}

#progress-bar {
    visibility: hidden;
    width: 100%;
    margin: 25px auto;
    border: solid 1px #000;
    border-radius: 10px;
}

#progress-bar-inner {
    height: 15px;
    border-radius: 10px;
    width: 100%;
    background-color: orange;
}
<p id="timer"></p>
<div id="progress-bar">
    <div id="progress-bar-inner"></div>
</div>

<br>
<button onclick="startTimerAndProgressbar()" id="start-btn">Start</button>
<button onclick="pauseTimerAndProgressbar()" id="pause-btn">Pause</button>
<button onclick="resumeTimerAndProgressbar()" id="resume-btn" disabled>Resume</button>

【讨论】:

  • 我认为你的回答很好,但随着计时器在0sec 结束,它会继续计数。
  • @AlanOmar;我不明白为什么会这样。如果将TIMELIMIT 更改为 1 秒,则内栏似乎与时间同步。
  • 虽然这似乎解决了问题,但它降低了代码的可读性......(例如,timeLeft = TIME_LIMIT*100;,其中timeLeftTIME_LIMIT 应该是单位second,因此与100相乘没有多大意义)
  • *100 是将所有内容转换为百分之一秒的一部分。如果以秒为单位,则动画没有任何中间值可供使用。
猜你喜欢
  • 2010-12-24
  • 2019-06-01
  • 2022-12-02
  • 2014-05-16
  • 2014-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
相关资源
最近更新 更多