与文本不同,为什么进度条不会动态变化?

时间:2015-05-17 09:05:20

标签: javascript jquery css twitter-bootstrap settimeout

我在setTimeout()函数后动态更新了一些元素。 jQuery函数.text()似乎在处理时随着数组索引的每次更改而动态更新。但是通过.css().attr()更改的引导程序进度条似乎无法动态更新。这是我的页面: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);
}

6 个答案:

答案 0 :(得分:10)

作为解释,很多答案都会指出大多数浏览器在UI线程上运行JavaScript 这一事实,因此在执行JavaScript时他们无法更新界面。相反,浏览器将wait for the Javascript to finish and return control to the UI thread

虽然记住这一点非常重要,但它并没有为您的代码发挥作用。如果您正在更新进度条,请执行以下操作:

for (i = 0; i < len; i++) {
    updateProgressBar(i)
};

然后它肯定会阻止UI更新直到结束。

但是你已经使用setTimeoutsetInterval做了正确的事情,它们在代码中有异步回调。这意味着JavaScript能够暂停足够长的时间来管理任何UI消息。事实证明文本能够动态更新。

正如您的问题所示,为什么,如果UI正在更新,进度条也不会更新?

答案在于Bootstrap applies the following CSSprogress bar

.progress-bar {
  -webkit-transition: width .6s ease;
       -o-transition: width .6s ease;
          transition: width .6s ease;
}

当通话之间的延迟为0毫秒时,浏览器 有时间更新用户界面,但 没有时间完成600毫秒的CSS转换。因此,直到最后你才能看到动画。

作为OhAuth points out,您可以通过使用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更改之前完成,在这种情况下延长延迟不会伤害。如果您想测试运行时间较长的流程,可以使用以下sleep function

function sleep(sleepyTime) {
  var start = +new Date;
  while (+new Date - start < sleepyTime){}
}

这是一个你可以玩的演示,每个设置都是一个变量,你可以配置它来看看它会如何反应,但最好的办法就是有条件地删除过渡。

Stack Snippets中的演示

&#13;
&#13;
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){}
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

这是由于bootstrap动画在进度条状态中的变化。如果超时间隔小于动画时间,则会对重绘进行排队。

尝试将此添加到进度条的CSS:

-webkit-transition: none;
transition: none;

Check my fiddle

答案 2 :(得分:0)

另一种解决方法(with reference to my previous answer):

如果必须保留动画,则可以使用保守的间隔延迟,例如100毫秒。延迟,用户不应该注意到。

答案 3 :(得分:0)

如果您确实需要将延迟计算为零,那么我会将计算和进度条值的设置分开,以便您在一个setInterval中计算值,然后单独运行{ {1}}每100毫秒将条形更新为此值。

这样您的计算是最新的,您的UI也需要更新时间。

如果你想在同一种方法中使用它们,那么我认为你需要添加至少100毫秒的延迟。

示例:https://jsfiddle.net/dk7g51g4/3/

使用Javascript:

setInterval

HTML:

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);
}

答案 4 :(得分:0)

这可能是一个重绘问题。由于延迟设置为0,因此在上次更新之前不会绘制CSS更改。

强制重绘的最简单方法是读取元素高度:

$("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer);
$("div[role='progressbar']").height();

答案 5 :(得分:0)

文字和进度条动态更改,但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);