【问题标题】:setTimeout function not working with for loopsetTimeout 函数不适用于 for 循环
【发布时间】:2016-08-04 22:31:35
【问题描述】:

我正在尝试运行此代码来制作包含 3 张图像的幻灯片,但它无法正常工作。幻灯片放映一次,然后就停止了...

下面是我的 JavaScript、CSS 和 HTML,如果你运行代码 sn-p 你会看到幻灯片运行了一次。

HTML 基本上是声明一个容器 div,其中幻灯片作为带有特定背景图像的 div。 (对于这个问题,我将图像更改为颜色,以便您可以看到幻灯片)

CSS 声明幻灯片中每个图像在普通视图中和隐藏时的位置。

JavaScript 在幻灯片中循环播放,当它们应该移出视图时,给每个幻灯片一个“隐藏”类。最后,它通过删除所有“隐藏”类来返回第一张幻灯片。

我很确定问题出在带有 setTimeout 函数的 JavaScript 中,因为每当我在控制台中运行这些函数时,它都能完美运行,但是当我尝试自动将它们设置为在我的 JS 中运行时,它只运行一次。

function slide1to2(){
	document.getElementById('slide1').className = "hidden";
	clearTimeout(s1to2);
}
function slide2to3(){
	document.getElementById('slide2').className = "hidden";
	clearTimeout(s2to3);
}
function slide3to1(){
	document.getElementById('slide1').className = "";
	document.getElementById('slide2').className = "";
	clearTimeout(s3to1);
}

for(i=0; i<100; i++){
	s1to2 = window.setTimeout(slide1to2, 2000);
	s2to3 = window.setTimeout(slide2to3, 4000);
	s3to1 = window.setTimeout(slide3to1, 6000);
}
div#slideshow{
	width:100%;
	height:50%;
	background-image:url("white-wall.png");
}

div#slideshow div{
	width:100%;
	height:inherit;
	background-repeat:no-repeat;
	background-position:center;
	background-color:rgba(0,0,0,0.5);
	position:absolute;
	transition:1s;
}

div#slideshow div[id$="1"]{
	background:#FF8888;
	transform:translateX(0%);
	z-index:3;
}

div#slideshow div[id$="2"]{
	background:#88FF88;
	transform:translateX(0%);
	z-index:2;
}

div#slideshow div[id$="3"]{
	background:#8888FF;
	transform:translateX(0%);
	z-index:1;
}

div#slideshow div[id$="1"].hidden{
	transform:translateX(-100%);
}

div#slideshow div[id$="2"].hidden{
	transform:translateX(-100%);
}
<div id="slideshow">
	<div id="slide1"></div>
	<div id="slide2"></div>
	<div id="slide3"></div>
</div>

【问题讨论】:

  • setTimeout() 是异步的。在计时器触发之前,它不会阻止执行。相反,它只是为将来的某个时间安排一个计时器并继续执行您的 javascript。因此,您在 for 循环中安排了 300 个计时器,全部在三个不同的时间。
  • 在你的 slideAtoB 函数中放入一些 console.log 语句,你会看到你在同一时刻得到了 100 个日志语句。

标签: javascript html for-loop slideshow settimeout


【解决方案1】:

当您setTimeout() 时,代码不会等待超时完成。这意味着您的 for 循环在 2 秒后执行 100 次,在 4 秒后再执行 100 次,在 6 秒后再执行 100 次。

除此之外,您可以在第三帧完成后重新设置超时。

一个带有超时的简单循环示例:

var i = 0;
function a() {
   //Do some stuff
   if (i++ < 100) setTimeout(a, 1000);
}

这个^很好。一个不好的例子是:

for (var i = 0; i < 100; i++) {
    setTimeout(function() {
        //Do stuff
    }, 1000);
}

第一个执行100次,间隔1秒,后者执行1次。

【讨论】:

    【解决方案2】:

    不使用带有 CSS3 动画的 JS 也可以得到相同的效果(代码不完全相同,你应该玩弄时代和样式)

    https://plnkr.co/edit/2AtRK7z9OJhs4AwX82rx?p=preview

    .animation--slideshowAnimation {
      width: 100%;
      height: 500px;
      background-size: cover;
      background-position: 50%;
      background-repeat: no-repeat;
    
      animation-duration: 12s;
      animation-name: slideshowAnimation;
      animation-delay: 0;
      animation-iteration-count: infinite;
      animation-direction: forward;
    }
    

    【讨论】:

      【解决方案3】:

      我得到了它的工作: (感谢 Yotam Salmon 的回答,这有助于我理解我做错了什么)

      我基本上让每个函数设置超时并运行以下一个,然后我让最后一个再次运行第一个。我需要的只是手动启动第一个,然后它就永远运行了。

      function slide1to2(){
          document.getElementById('slide1').className = "hidden";
          setTimeout(slide2to3, 4000);
      }
      function slide2to3(){
          document.getElementById('slide2').className = "hidden";
          setTimeout(slide3to1, 4000);
      }
      function slide3to1(){
          document.getElementById('slide1').className = "";
          document.getElementById('slide2').className = "";
          setTimeout(slide1to2, 4000);
      }
      
      slide1to2();
      div#slideshow{
      	width:100%;
      	height:50%;
      	background-image:url("white-wall.png");
      }
      
      div#slideshow div{
      	width:100%;
      	height:inherit;
      	background-repeat:no-repeat;
      	background-position:center;
      	background-color:rgba(0,0,0,0.5);
      	position:absolute;
      	transition:1s;
      }
      
      div#slideshow div[id$="1"]{
      	background:#FF8888;
      	transform:translateX(0%);
      	z-index:3;
      }
      
      div#slideshow div[id$="2"]{
      	background:#88FF88;
      	transform:translateX(0%);
      	z-index:2;
      }
      
      div#slideshow div[id$="3"]{
      	background:#8888FF;
      	transform:translateX(0%);
      	z-index:1;
      }
      
      div#slideshow div[id$="1"].hidden{
      	transform:translateX(-100%);
      }
      
      div#slideshow div[id$="2"].hidden{
      	transform:translateX(-100%);
      }
      <div id="slideshow">
          <div id="slide1"></div>
          <div id="slide2"></div>
          <div id="slide3"></div>
      </div>

      【讨论】:

      • 您知道这几乎就是我发布的内容吗?但是,您没有将其标记为已接受的答案?
      【解决方案4】:

      正如其他人所提到的,您的循环实际上什么都不做,因为 setTimeout 是异步的。

      实现你想要的结果的一种方法是在每个中设置回调函数。然后设置另一个将清除超时的功能。要永远循环,只需删除 stopTransitions 函数及其调用者即可。

      https://jsfiddle.net/24aLyg5v/

      var timeout1, timeout2;
      
      function slide1to2(){
          document.getElementById('slide1').className = "hidden";
          document.getElementById('slide2').className = "";
          timeout1 = window.setTimeout(slide2to1, 2500);
      }
      
      function slide2to1(){
          document.getElementById('slide2').className = "hidden";
          document.getElementById('slide1').className = "";
          timeout2 = window.setTimeout(slide1to2, 2500);
      }
      
      function stopTransitions() {
          clearTimeout(timeout1);
          clearTimeout(timeout2);
      }
      
      window.setTimeout(stopTransitions, 20000);
      slide1to2();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-19
        • 1970-01-01
        • 2021-03-06
        • 2018-03-13
        • 1970-01-01
        • 1970-01-01
        • 2014-01-29
        • 2014-12-27
        相关资源
        最近更新 更多