为什么 Progress Bar 不像 Text 那样动态变化?
Why doesn't Progress Bar dynamically change unlike Text?
我正在 setTimeout()
函数后动态更新一些元素。 jQuery 函数 .text()
似乎在处理时随着数组索引的每次更改而动态更新。但是通过 .css()
和 .attr()
更改的 bootstrap 进度条似乎不会动态更新。这是我的页面:http://imdbnator.com/process.php?id=f144caf0843490c0d3674113b03da0c5&redirect=false
您可以看到文本已更改,但进度条仅在整个 setTimeout()
函数完成后才结束。另外,如果我设置 delay = 1000
。有用。但它会因应用程序而减慢。因此,我需要delay = 0
。但是为什么进度条没有变化?
这是我的片段
function launch(a) {
var inc = 0;
var maxc = a.length;
var delay = 0; // delay milliseconds
var iID = setInterval(function () {
var index = inc;
var movie = a[inc];
//start processing function
//styling while processing
var markerPer = ((index + 1) / rawListNum) * 100; // marker percentage
$("#procNum").text("(" + (index + 1) + "/" + rawListNum + ")"); //Processing number
$("#procMovie").text(movie); //Processing Name
$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer); // progress bar -> DOES NOT WORK
if (++inc >= maxc) clearInterval(iID);
},
delay);
}
这是由于 bootstrap 动画进度条状态变化的方式所致。如果超时间隔小于动画时间,它将对重绘进行排队。
尝试将此添加到进度条的 CSS:
-webkit-transition: none;
transition: none;
另一种解决方法 ():
如果必须保留动画,可以使用保守的间隔延迟,比如 100 毫秒。用户不应注意到的延迟。
如果你真的需要计算延迟为零那么我会把计算和进度条值的设置分开,这样你就可以在一个setInterval
中计算这个值,然后运行 一个单独的 setInterval
,每 100 毫秒将条形更新为此值。
这样你的计算是最新的,你的 UI 也有时间需要更新。
如果您希望它们都使用相同的方法,那么我认为您需要添加至少 100 毫秒的延迟。
示例:https://jsfiddle.net/dk7g51g4/3/
Javascript:
var _ValueToSet = 0;
$(document).ready(function () {
// SET VALUE EXTREMELY FAST (your current code)
setInterval(function () {
_ValueToSet = Math.round(Math.random() * 100); // get value we are going to set
}
, 0); // run as fast as possible
// RUN UI UPDATE AT 100MS (separate thread for ui updates).
setInterval(function () {
setRandom()
}
, 100); // give ui 100ms to do its thing
});
function setRandom() {
var elem = $('.progress-bar'); // what is our target progress bar
// set both style width and aria-valuenow
elem.css('width', _ValueToSet + '%');
elem.attr('aria-valuenow', _ValueToSet);
}
HTML:
<div class="progress progress-striped active">
<div class="progress-bar"
style="width:0%"
role="progressbar"
aria-valuenow="0"
aria-valuemin="30"
aria-valuemax="100">
</div>
</div>
这可能是重绘问题。由于延迟设置为 0,因此 CSS 直到最后一次更新才会绘制更改。
强制重绘的最简单方法是读取元素高度:
$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer);
$("div[role='progressbar']").height();
文本和进度条动态变化,但 delay === 0
非常快:(http://jsfiddle.net/sergdenisov/mh4o1wxz/1/):
HTML:
<div class="text">Text</div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;">
</div>
</div>
Javascript:
var delay = 0;
var percent = 0;
var iID = setInterval(function() {
percent += 10;
$('.text').text('Text ' + percent + '/100');
$('.progress-bar').css('width', percent + '%').attr('aria-valuenow', percent);
if (percent === 100) {
clearInterval(iID);
}
}, delay);
作为解释,很多答案都会指出这样一个事实,大多数浏览器 运行 JavaScript 在 UI 线程 ,所以他们无法在执行 JavaScript 时更新界面。相反,浏览器将 wait for the Javascript to finish and return control to the UI thread.
虽然记住这一点很重要,但它对您的代码不起作用。如果您正在更新进度条,请执行以下操作:
for (i = 0; i < len; i++) {
updateProgressBar(i)
};
那肯定会阻止UI更新到最后。
但是您已经通过使用 setTimeout
or setInterval
做了正确的事情,它在代码中有异步回调。这意味着 JavaScript 能够暂停足够长的时间来传送任何 UI 消息。事实证明,文本能够动态更新。
正如您的问题所问,为什么 UI 正在更新,进度条是否也没有更新?
答案在于Bootstrap applies the following CSS to the progress bar:
.progress-bar {
-webkit-transition: width .6s ease;
-o-transition: width .6s ease;
transition: width .6s ease;
}
当调用之间的延迟为 0 毫秒时,浏览器没有有时间更新UI,但没有有时间完成 600 毫秒 CSS 过渡。因此,您直到结束才看到动画。
作为,你可以通过CSS去除过渡效果来防止浏览器延迟宽度更新,像这样:
.progress .progress-bar {
-webkit-transition: none;
-o-transition: none;
transition: none;
}
如果您循环浏览大量项目,增量更新将提供某种动画效果。如果您想保留通用用例的样式,您可以在代码中关闭和打开转换。从 jQuery 1.8 you can update CSS properties without the vendor prefix 开始,您只需调用 .css("transition","none")
.
当然,根据您为每部电影所做的工作量,JavaScript 可能会在您可以目测到所有 UI 更改之前完成,在这种情况下延长延迟不会造成伤害。如果您想测试更长的 运行ning 进程,您可以使用以下 sleep function:
function sleep(sleepyTime) {
var start = +new Date;
while (+new Date - start < sleepyTime){}
}
这是一个演示,您可以尝试其中的每个设置都是一个变量,您可以配置该变量以查看它会如何反应,但最好的办法是有条件地删除过渡。
堆栈片段中的演示
var delay, numMovies, throttledMovies, sleepTime, removeTransition;
$("#delay").change(function(){ delay = this.value }).change()
$("#movies").change(function(){ numMovies = this.value }).change()
$("#sleep").change(function(){ sleepTime = this.value }).change()
$("#transition").change(function(){ removeTransition = this.checked }).change()
$("#loadMovies").click(loadMovies);
function loadMovies() {
var i = 0;
throttledMovies = Movies.slice(0, numMovies)
if (removeTransition) {
$('#progress-bar-movie').css("transition","none");
}
var interval = setInterval(function () {
loadMovie(i)
if (++i >= numMovies) {
clearInterval(interval);
$('#progress-bar-movie').css("transition","width .6s ease");
}
}, delay);
};
function loadMovie(i) {
var movie = throttledMovies[i];
var percentComplete = ((i + 1) / numMovies) * 100;
sleep(sleepTime);
// update text
$("#procNum").text("(" + (i + 1) + "/" + numMovies + ")");
$("#procMovie").text(movie.Title);
// update progress bar
$('#progress-bar-movie')
.css('width', percentComplete+'%')
.attr('aria-valuenow', percentComplete);
};
function sleep(sleepyTime) {
var start = +new Date;
while (+new Date - start < sleepyTime){}
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<script src="http://kylemitofsky.com/libraries/libraries/movies.js"></script>
<!-- params -->
<label for="delay">Delay (ms)</label>
<input type="number" value="0" min=0 max=1000 id="delay"/>
<label for="movies"># Movies </label>
<input type="number" value="250" min=0 max=250 id="movies"/>
<label for="sleep">Sleep time (ms)</label>
<input type="number" value="0" min=0 max=1000 id="sleep"/>
<label for="transition">Remove transition? </label>
<input type="checkbox" checked="true" id="transition"/><br/><br/>
<button class="btn btn-primary btn-lg" id="loadMovies">
Load Movies
</button><br/><br/>
<p>
<b>Current Title</b>: <span id="procMovie"></span><br/>
<b>Progress</b>: <span id="procNum"></span>
</p>
<div class="progress">
<div class="progress-bar" role="progressbar" id="progress-bar-movie"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
我正在 setTimeout()
函数后动态更新一些元素。 jQuery 函数 .text()
似乎在处理时随着数组索引的每次更改而动态更新。但是通过 .css()
和 .attr()
更改的 bootstrap 进度条似乎不会动态更新。这是我的页面:http://imdbnator.com/process.php?id=f144caf0843490c0d3674113b03da0c5&redirect=false
您可以看到文本已更改,但进度条仅在整个 setTimeout()
函数完成后才结束。另外,如果我设置 delay = 1000
。有用。但它会因应用程序而减慢。因此,我需要delay = 0
。但是为什么进度条没有变化?
这是我的片段
function launch(a) {
var inc = 0;
var maxc = a.length;
var delay = 0; // delay milliseconds
var iID = setInterval(function () {
var index = inc;
var movie = a[inc];
//start processing function
//styling while processing
var markerPer = ((index + 1) / rawListNum) * 100; // marker percentage
$("#procNum").text("(" + (index + 1) + "/" + rawListNum + ")"); //Processing number
$("#procMovie").text(movie); //Processing Name
$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer); // progress bar -> DOES NOT WORK
if (++inc >= maxc) clearInterval(iID);
},
delay);
}
这是由于 bootstrap 动画进度条状态变化的方式所致。如果超时间隔小于动画时间,它将对重绘进行排队。
尝试将此添加到进度条的 CSS:
-webkit-transition: none;
transition: none;
另一种解决方法 (
如果必须保留动画,可以使用保守的间隔延迟,比如 100 毫秒。用户不应注意到的延迟。
如果你真的需要计算延迟为零那么我会把计算和进度条值的设置分开,这样你就可以在一个setInterval
中计算这个值,然后运行 一个单独的 setInterval
,每 100 毫秒将条形更新为此值。
这样你的计算是最新的,你的 UI 也有时间需要更新。
如果您希望它们都使用相同的方法,那么我认为您需要添加至少 100 毫秒的延迟。
示例:https://jsfiddle.net/dk7g51g4/3/
Javascript:
var _ValueToSet = 0;
$(document).ready(function () {
// SET VALUE EXTREMELY FAST (your current code)
setInterval(function () {
_ValueToSet = Math.round(Math.random() * 100); // get value we are going to set
}
, 0); // run as fast as possible
// RUN UI UPDATE AT 100MS (separate thread for ui updates).
setInterval(function () {
setRandom()
}
, 100); // give ui 100ms to do its thing
});
function setRandom() {
var elem = $('.progress-bar'); // what is our target progress bar
// set both style width and aria-valuenow
elem.css('width', _ValueToSet + '%');
elem.attr('aria-valuenow', _ValueToSet);
}
HTML:
<div class="progress progress-striped active">
<div class="progress-bar"
style="width:0%"
role="progressbar"
aria-valuenow="0"
aria-valuemin="30"
aria-valuemax="100">
</div>
</div>
这可能是重绘问题。由于延迟设置为 0,因此 CSS 直到最后一次更新才会绘制更改。
强制重绘的最简单方法是读取元素高度:
$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer);
$("div[role='progressbar']").height();
文本和进度条动态变化,但 delay === 0
非常快:(http://jsfiddle.net/sergdenisov/mh4o1wxz/1/):
HTML:
<div class="text">Text</div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;">
</div>
</div>
Javascript:
var delay = 0;
var percent = 0;
var iID = setInterval(function() {
percent += 10;
$('.text').text('Text ' + percent + '/100');
$('.progress-bar').css('width', percent + '%').attr('aria-valuenow', percent);
if (percent === 100) {
clearInterval(iID);
}
}, delay);
作为解释,很多答案都会指出这样一个事实,大多数浏览器 运行 JavaScript 在 UI 线程 ,所以他们无法在执行 JavaScript 时更新界面。相反,浏览器将 wait for the Javascript to finish and return control to the UI thread.
虽然记住这一点很重要,但它对您的代码不起作用。如果您正在更新进度条,请执行以下操作:
for (i = 0; i < len; i++) {
updateProgressBar(i)
};
那肯定会阻止UI更新到最后。
但是您已经通过使用 setTimeout
or setInterval
做了正确的事情,它在代码中有异步回调。这意味着 JavaScript 能够暂停足够长的时间来传送任何 UI 消息。事实证明,文本能够动态更新。
正如您的问题所问,为什么 UI 正在更新,进度条是否也没有更新?
答案在于Bootstrap applies the following CSS to the progress bar:
.progress-bar {
-webkit-transition: width .6s ease;
-o-transition: width .6s ease;
transition: width .6s ease;
}
当调用之间的延迟为 0 毫秒时,浏览器没有有时间更新UI,但没有有时间完成 600 毫秒 CSS 过渡。因此,您直到结束才看到动画。
作为
.progress .progress-bar {
-webkit-transition: none;
-o-transition: none;
transition: none;
}
如果您循环浏览大量项目,增量更新将提供某种动画效果。如果您想保留通用用例的样式,您可以在代码中关闭和打开转换。从 jQuery 1.8 you can update CSS properties without the vendor prefix 开始,您只需调用 .css("transition","none")
.
当然,根据您为每部电影所做的工作量,JavaScript 可能会在您可以目测到所有 UI 更改之前完成,在这种情况下延长延迟不会造成伤害。如果您想测试更长的 运行ning 进程,您可以使用以下 sleep function:
function sleep(sleepyTime) {
var start = +new Date;
while (+new Date - start < sleepyTime){}
}
这是一个演示,您可以尝试其中的每个设置都是一个变量,您可以配置该变量以查看它会如何反应,但最好的办法是有条件地删除过渡。
堆栈片段中的演示
var delay, numMovies, throttledMovies, sleepTime, removeTransition;
$("#delay").change(function(){ delay = this.value }).change()
$("#movies").change(function(){ numMovies = this.value }).change()
$("#sleep").change(function(){ sleepTime = this.value }).change()
$("#transition").change(function(){ removeTransition = this.checked }).change()
$("#loadMovies").click(loadMovies);
function loadMovies() {
var i = 0;
throttledMovies = Movies.slice(0, numMovies)
if (removeTransition) {
$('#progress-bar-movie').css("transition","none");
}
var interval = setInterval(function () {
loadMovie(i)
if (++i >= numMovies) {
clearInterval(interval);
$('#progress-bar-movie').css("transition","width .6s ease");
}
}, delay);
};
function loadMovie(i) {
var movie = throttledMovies[i];
var percentComplete = ((i + 1) / numMovies) * 100;
sleep(sleepTime);
// update text
$("#procNum").text("(" + (i + 1) + "/" + numMovies + ")");
$("#procMovie").text(movie.Title);
// update progress bar
$('#progress-bar-movie')
.css('width', percentComplete+'%')
.attr('aria-valuenow', percentComplete);
};
function sleep(sleepyTime) {
var start = +new Date;
while (+new Date - start < sleepyTime){}
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<script src="http://kylemitofsky.com/libraries/libraries/movies.js"></script>
<!-- params -->
<label for="delay">Delay (ms)</label>
<input type="number" value="0" min=0 max=1000 id="delay"/>
<label for="movies"># Movies </label>
<input type="number" value="250" min=0 max=250 id="movies"/>
<label for="sleep">Sleep time (ms)</label>
<input type="number" value="0" min=0 max=1000 id="sleep"/>
<label for="transition">Remove transition? </label>
<input type="checkbox" checked="true" id="transition"/><br/><br/>
<button class="btn btn-primary btn-lg" id="loadMovies">
Load Movies
</button><br/><br/>
<p>
<b>Current Title</b>: <span id="procMovie"></span><br/>
<b>Progress</b>: <span id="procNum"></span>
</p>
<div class="progress">
<div class="progress-bar" role="progressbar" id="progress-bar-movie"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>