我可以看到这里有几个类似的问题,但不幸的是我找不到我期望的答案。 我是编程新手,并尝试使用Javascript Progress Bar。我有一个计数器倒计时,只要进度条超出宽度但我遇到了问题,当焦点中的选项卡处于非活动状态时,进度条会暂停,从而保持计数器不倒计时。 我有了使用网络工作者http://www.tutorialspoint.com/html5/html5_web_workers.htm的想法,但我无法让它工作。我很感激我到这里的任何形式的帮助。 以下是我的代码。
<!DOCTYPE html>
<html>
<head>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/
jquery.min.js">
</script>
<style>
#progressContainer {
position: relative;
width: 97%;
height: 25px;
background-color: #ddd;
margin-bottom: 15px;
}
#progressBar {
position: absolute;
width: 0%;
height: 100%;
background-color: #A9A9A9;
}
#container{
width: 200px;
height: 200px;
border: 1px solid black;
padding: 10px
}
</style>
<script>
$(document).ready(function(){
$("#countDownBtn").click(function(){
var cdNumber = $("#countDownId").val();
var id = setInterval(frame, 100);
var elem = document.getElementById("progressBar");
var progressBarWidth = 101;
function frame() {
if (progressBarWidth === 0) {
clearInterval(id);
cdNumber--;
$("#countDownId").val(cdNumber);
console.log(cdNumber);
if (cdNumber === 0) {
clearInterval(id);
}
else {
elem.style.width = '100%';
progressBarWidth = 100;
//alert("Hi");
}
}
else {
progressBarWidth--;
elem.style.width = progressBarWidth + '%';
}
}
});
});
</script>
</head>
<body>
<div id="container">
<div>
<input type="text" id="countDownId" value="">
<button id="countDownBtn" class="btn">Click</button>
</div><br>
<div id="progressContainer">
<div id="progressBar"></div>
</div>
</div>
</body>
答案 0 :(得分:1)
根据某个区间的精确度,你总会遇到这样的问题;甚至是requestAnimationFrame
。他们不精确。
更好的方法(不仅仅是在这种情况下,但几乎每次都必须转换一个值)是保存startTime并计算间隔中的传递时间(如@ Nosyara已经建议)。
当处理缩放因子和/或暂停这些东西时,事情会再次变得混乱。这是一个执行此任务的实用程序:
// The basic concept of this "Clock" is a linear equation over Date.now()
// plus the logic to make this equation pausable.
// therefore it's completely independant of **any** interval; it's just math.
function Clock(v){
var p=true,m=1,b=+v||0,n=Clock.now;
return Object.assign(Object.create(Clock.prototype),{
// getter() / setter(value)
// I don't use real getter and setter, because this syntax
// allows/implements method-chaining
value(v){return arguments.length?(b=(+v||0)-(!p&&m*n()),this):b+(!p&&m*n())},
speed(v){return arguments.length?(v=+v||0,p||v===m||(b+=n()*(m-v)),m=v,this):m},
paused(v){return arguments.length?(((v=!!v)===p)||(b+=n()*((p=v)?m:-m)),this):p},
});
}
Object.assign(Clock.prototype,{
valueOf(){return this.value()},
//aliases for setting the paused() state; doesn't matter if you call them repeatedly.
start(){return this.paused(false)},
stop(){return this.paused(true)},
});
Clock.now=Date.now; //the function used for timing
//Clock.now=performance&&performance.now?performance.now.bind(performance):Date.now;
现在你的代码:
$(function(){
function frame(){
//yes, countDown get's converted to Number
var value = Math.max(0, countDown);
var count = Math.ceil(value);
var progress = value % 1;
$progressBar.width( progress * 100 + "%" );
//so that I don't update $countDown.val() on every frame, but only if necessary
//on the other hand, it wouldn't be that bad.
if(count !== lastCount) $countDown.val( lastCount = count );
//either stop the countDown or request the next frame.
if(value > 0) requestAnimationFrame(frame);
else countDown.stop();
}
//create a Clock and set speed. Clock is paused by default.
var countDown = Clock().speed( -1 / 10000/*ms*/ );
var $progressBar = $("#progressBar");
var $countDown = $("#countDownId");
var lastCount;
$("#countDownBtn").click(function(){
//if !countDown.paused() then there already is a pending `requestAnimationFrame(frame)`
//from the last call of frame()
if(countDown.paused()) requestAnimationFrame(frame);
countDown.value( $countDown.val() ).start();
});
})
答案 1 :(得分:0)
我在Chrome浏览器的某个项目中遇到了类似的问题。问题的根源是,如果标签未处于活动状态,Chrome每秒最多允许1个计时器事件(setTimeout或setInterval)。如果每秒有多于1个调用 - 它创建队列,则页面行为取决于事件内部的逻辑,并且可能看起来不像预期的那样。解决方案之一是检查页面的可见性并管理间隔Check here
答案 2 :(得分:0)
您可以使用setTimeout并使用递归。它可能看起来像这样:
var stopInterval = false;
frame();
function frame() {
if(stopInterval) return;
// Your stuff to run in interval HERE
setTimeout(frame, 100);
}
旧版浏览器不支持Webworkers。浏览器还指定它们如何单独处理非活动选项卡上的setTimeout和setInterval,因此行为可能不同。 Chrome似乎减慢了递归速度(每秒1次?)。
答案 3 :(得分:0)
正如@ManoDestra在评论中指出的那样,你应该使用requestAnimationFrame而不是setInterval。
我建议的最佳解决方案是利用HTML5 Visibility API检测选项卡在处于非活动状态后何时再次处于活动状态,然后相应地更新进度条。也许您可以在初始化时存储倒计时的时间戳,并且当标签再次变为活动状态时,您会查看新的时间戳并进行比较。
答案 4 :(得分:0)
特别是在您的情况下,您可以使用时钟时间来表示正确的进度。当您不希望信任浏览器关于间隔事件时。 假设您想要10秒倒计时:
var tm = new Date().getTime() + 10000; // 10 sec in milliseconds
setInterval(function(){
var secondsPassed = (tm - new Date().getTime()) / 1000;
// update UI
}, 100); // You can use variable here in different visibility modes