为什么Progress Bar不会像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); }
通过解释,很多答案都会指出大多数浏览器在UI线程上运行JavaScript的事实,因此在执行JavaScript时它们无法更新界面。 相反,浏览器将等待Javascript完成并将控制权返回给UI线程 。
虽然记住这一点非常重要,但它并没有为您的代码发挥作用。 如果您正在更新进度条,请执行以下操作:
for (i = 0; i < len; i++) { updateProgressBar(i) };
然后它肯定会阻止UI更新直到结束。
但是你已经通过使用setTimeout
或setInterval
做了正确的事情,它们在代码中有异步回调。 这意味着JavaScript能够暂停足够长的时间来管理任何UI消息。 事实certificate文本能够动态更新。
正如您的问题所问,为什么,如果UI正在更新,进度条也不会更新?
答案在于Bootstrap将以下CSS应用于进度条 :
.progress-bar { -webkit-transition: width .6s ease; -o-transition: width .6s ease; transition: width .6s ease; }
当调用之间的延迟为0ms时,浏览器确实有时间更新UI,但没有时间完成600ms的CSS转换。 因此,直到最后才能看到动画。
正如OhAuth指出的那样 ,您可以通过使用CSS删除过渡效果来阻止浏览器延迟宽度更新:
.progress .progress-bar { -webkit-transition: none; -o-transition: none; transition: none; }
如果您循环遍历大量项目,增量更新将提供某种动画。 如果您想留下通用用例的样式,可以在代码中关闭和打开转换。 从jQuery 1.8开始,您可以在没有供应商前缀的情况下更新CSS属性 ,因此您只需要调用.css("transition","none")
。
当然,根据您为每部电影所做的工作量,JavaScript可以在您可以直观地检测所有UI更改之前完成,在这种情况下延长延迟不会受到影响。 如果您想测试更长时间运行的进程,可以使用以下睡眠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){} }
Current Title:
Progress:
这是由于bootstrap动画在进度条状态中的变化。 如果超时间隔小于动画时间,则会将重绘排队。
尝试将此添加到进度条的CSS:
-webkit-transition: none; transition: none;
检查我的小提琴
另一项工作( 参考我以前的答案 ):
如果必须保留动画,则可以使用保守的间隔延迟,例如100毫秒。 用户不应注意的延迟。
如果您确实需要将延迟设置为零以进行计算,那么我将分离计算和进度条值的设置,以便您在一个setInterval
中计算值,然后运行单独的setInterval
,每隔100 ms更新一次条形图达到这个价值。
这样您的计算是最新的,您的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:
这可能是一个重绘问题。 由于延迟设置为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:
Text
使用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);