【问题标题】:SetTimeout inside a for loop在 for 循环中设置超时
【发布时间】:2016-10-13 16:37:32
【问题描述】:

我正在尝试编写一个脚本来更改 3 个图像的 z-index。基本上,脚本应该针对当前图像并在下一张图像上应用更高的 z-index,就像一种轮播,但使用 z-index 而不是活动类。挑战是在特定时间间隔后设置 z-index。问题是显示第一张图像,然后显示最后一张。这是我的代码:

HTML:

<div class="changingimages">
    <img src="#" data-time="3000" width="100%" class="alternateimage alternateimage1">
    <img src="#" data-time="2000" width="100%" class="alternateimage alternateimage2">
    <img src="#" data-time="4000" width="100%" class="alternateimage alternateimage3">
</div>

jQuery 脚本

<script type="text/javascript">

jQuery(document).ready(function(){

    var changeImg = function(i, time, currentImg) {

        setTimeout(function(){

            jQuery(currentImg).next().css("z-index", i);

        }, time);
    };

    var numberOfChilds = jQuery(".changingimages").children().length;
    var currentIndexClass;
    var currentImg;
    var time;

    for (var i=1; i<=numberOfChilds; i++) {

            currentIndexClass = '.alternateimage' + i;
            currentImg = jQuery(currentIndexClass);
            time = jQuery(currentIndexClass).attr("data-time");

            changeImg(i, time, currentImg);

    }

});

我认为循环内的闭包存在一些问题,但不确定!

【问题讨论】:

  • 什么您遇到的问题是什么?什么不起作用?
  • @DavinTryon:不,仔细看一下代码。
  • @M.Simon 这是预期的,是的:两秒钟内,没有 z-index;然后将 2 的 z-index 应用于最后一张图像(然后在 3 秒后,将 z-index 1 应用于第二张图像,并在 4 秒后将 z-index 3 应用于无图像)。代码实际上应该做什么?也许您想删除.next()
  • 您是否真的希望您的data-time 属性不按顺序排列?我们不知道您是打算从初始函数调用还是从之前的 setTimeout 开始持续时间
  • setTimeout 不会暂停脚本。实际上,2000ms 计时器将首先执行,然后是 3000ms 计时器,最后是 4000ms 计时器。所以最后一个发生在你的循环后总共 4 秒,而不是 9 秒。呼叫的顺序无关紧要。虽然下面的答案提供了一个解决方案,但我倾向于只调用第一个,然后从 setTimeout 中进行递归调用。

标签: javascript jquery for-loop settimeout


【解决方案1】:

setTimeout 安排事件相对于先前排队的事件运行是一个常见的误解。从理论上讲,您似乎相信以下几点:

setTimeout(f, 100);
setTimeout(g, 100);
setTimeout(h, 100);

会产生这样的时间线:

0ms   Start
100ms Run f()
200ms Run g()
300ms Run h()

实际情况是setTimeout 中的时间选项表示“至少经过这么多时间后运行此函数”。离开前面的例子,你实际上会得到更像

0ms   Start
100ms Run f()
101ms Run g()
102ms Run h()

要正确间隔代码,请不断增加超时时间,而不是替换它。

var time = 0;

for (var i = 1; i <= numberOfChilds; i++) {
  currentIndexClass = '.alternateimage' + i;
  currentImg = jQuery(currentIndexClass);

  // Add to the previous time
  time += parseInt(jQuery(currentIndexClass).attr("data-time"), 10);
  changeImg(i, time, currentImg);
}

【讨论】:

  • 要添加它们,您可能必须先将它们转换为数字
  • @Bergi 真的。已更正。
【解决方案2】:

这是一个实现使用超时来实现你想要的东西的小提琴。

fiddle

.textArea {
  position: absolute;
  height: 50px;
  width: 50px;
  display: block;
}

.box_a {
  background-color: blue;
}

.box_b {
  background-color: red;
}

.box_c {
  background-color: orange;
}

.active {
  z-index: 3;
}


<div class="textArea box_a active">a</div>
<div class="textArea box_b">b</div>
<div class="textArea box_c">c</div>

$(function(){
  var $elem = $('.textArea');

  timeout(0);

  function timeout(i){
    $($elem[i]).addClass('active');
    return setTimeout(function(){
      $elem.removeClass('active');
      i++;
      if(i >= $elem.length){
        i = 0
      }
      timeout(i);
    }, 1000)
  }
});

注意它不使用 for 循环,因为超时是异步的,不会按顺序执行。每个超时基本上会同时触发,然后根据等待时间执行它们的动作。

解决方案是创建一个函数来跟踪索引,以及最后一次超时何时完成执行。

【讨论】:

  • 不错的脚本。我也试试这个。谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 2011-11-19
  • 2022-10-24
  • 2019-01-23
  • 2013-09-27
相关资源
最近更新 更多