jQuery 中的 setTimeout 循环

setTimeout in jQuery with a loop

我有一个单词数组,我想延迟按顺序为每个单词更改一个 div 标签。

<script>
    function printWord(w) {
    setTimeout(function() {
        $("#word").text(w);
        }, 1000);

     }

function readBook() {
    var array = $("#offscreen_text").text().toString().split(/[\s\n]+/);
    for (i =1; i < array.length; i++){
        printWord(array[i]);
    }

}
</script>
<body onload="readBook()">
<div id="word"></div>
<div id="offscreen_text">hi hello bye goodbye this is a test with some random text</div>
</body>

当我 运行 readBook() 似乎什么都没发生。

数组索引从 0 开始。

for (i = 1; i < array.length; i++)

应该是

for (i = 0; i < array.length; i++)
//       ^

printWord(w)

不考虑连续延迟。第一次调用它时,它会告诉脚本在继续之前等待 1000 毫秒,并且每次后续调用(将在上一次调用后大约 1ms 发生)将 等待 1000 毫秒。这意味着脚本将在显示最后一个字之前等待大约 1 秒。

如果您要继续使用 setTimeout,请将函数更改为以下内容:

function printWord(w, d) {
    setTimeout(function() {
        $("#word").text(w);
    }, 1000 * d);
}

您正在使用 jQuery 作为依赖项。 Read the API and USE IT,或删除依赖项。

.text() 总是 returns 一个字符串。 .toString() 是不必要的。摆脱它。

$("#offscreen_text").text().toString().split(/[\s\n]+/);
//                         ^^^^^^^^^^^

此外,\s 匹配 \n,因此 [\s\n] 是多余的。简化为 /\s+/

jQuery(function ($) {})document.ready 的别名简写,这是调用 readBook:

的适当方式
function readBook($) {
    ...
}

jQuery(readBook);

setTimeout 没有排队行为。使用 delay(1000)queue(fn):

function printWord(w) {
    $('#word').delay(1000).queue(function (next) {
        $(this).text(w);
    });
}

您在使用简单的 for 循环进行迭代时犯了一个错误。 jQuery 有一个实用的 $.each 方法可以防止这样一个简单的错误:

$.each(array, function (index, value) {
    ...
});

现在一起

jQuery(function ($) {
  var words;
  words = $('#offscreen_text').text().split(/\s+/);
  $.each(words, function (i, word) {
    $('#word').delay(1000).queue(function (next) {
      $(this).text(word);
      next();
    });
  });
});
#offscreen_text {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="word"></div>
<div id="offscreen_text">hi hello bye goodbye this is a test with some random text</div>

http://jsfiddle.net/ta9q32v7/

function readBook() {
    var array = $("#offscreen_text").text().toString().split(/[\s\n]+/);
    var i = 0;
    setInterval(function(){ $("#word").text(array[i % array.length]); i++;}, 1000);
}

readBook();

我已经为您创建了一个带有解决方案的 jsfiddle。未调用 readBook() 方法。如果你确实按照你的方式调用它,它看起来好像只做了数组的最后一个字,因为 setTimeouts 会同时发生,因为它们都是在迭代循环时调用的(几乎同时时间)...为了解决这个问题,我只是在超时中添加了一个乘数,表示你在循环中的距离。这个解决方案可能不是很有效,因为它会设置与单词一样多的超时。

另外,你有 i=1 其他人说会跳过数组的第一个单词。

http://jsfiddle.net/782pmv64/2/

function printWord(w, i) {
  setTimeout(function() {
    $("#word").text(w);
    }, 800 * i);
}

您可以在不使用 for 循环的情况下使用 setInterval。

function readBook() {
    var array = $("#offscreen_text").text().toString().split(/[\s\n]+/);
    var i=0;
    setInterval(function(){
        $("#word").text(array[i]); i++;    
    },1000);   
}

演示:http://jsfiddle.net/sywzno5p/

使用 clearInterval() 编辑 Fiddle:http://jsfiddle.net/gn6eh7t1/

你一遍又一遍地调用 printWord 函数,没有给它时间来执行代码,所以每次 运行s,它都会覆盖之前的 运行,只给它打印的机会最后一句话...

我将您的代码修改为一个函数,它只在知道还有更多单词要 "read" 时才调用自身。

我在全局范围内声明了数组以及字数统计的迭代器。一旦一个单词 'read',函数 readBook 将递增迭代器。

请运行 代码段。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="word"></div>
<div id="offscreen_text">hi hello bye goodbye this is a test with some random text</div>
<script>
  var i = 0;
  var array = $("#offscreen_text").text().toString().split(/[\s\n]+/);

  function readBook() {

    $("#word").text(array[i]);
    i++;
    if (i < array.length) {
      setTimeout(readBook, 1000);
    }


  }



  readBook();
</script>

问题:

  1. 所有 printWord 调用是同时进行的,因此函数内的每个 setInterval 调用将大致同时触发。
  2. 数组索引从 0 开始,因此 i =1 将跳过第一个单词。
  3. 虽然不是问题,但令人不快,但是在使用[=46=时不需要使用onload,您可以使用jQuery的document.ready.
  4. 此外,无需在 $("#offscreen_text").text() 上调用 .toString(),因为 jQuery.text 将始终 return 一个字符串,即使没有选择任何元素。

一个解决方案:

您可以使用基于 setTimeout 的循环来遍历单词。

$(function() {//document.ready wrapper (no need for onload).
  function readBook() {
    var array = $("#offscreen_text").text().split(/[\s\n]+/);
    var wordIndex = 0;//Keep track of the word to show.
    var nextWord = function() {
      if (wordIndex < array.length) {//Check if there are more words to show.
        $("#word").text(array[wordIndex]);//Set the word.
        setTimeout(nextWord, 1000);//Set the next word timeout.
        wordIndex++;//Increment the word counter.
      }
    }
    nextWord();//Start the word loop.
  }
  readBook();
});
#offscreen_text {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="word"></div>
<div id="offscreen_text">hi hello bye goodbye this is a test with some random text</div>

不喜欢把这样的事情复杂化,解决方案可以像

一样简单
function printWord(word,index,life) {
    setTimeout(function() {
         $("#word").text(word);
    }, index*life);

}

function readBook() {
    var array = $("#offscreen_text").text().split(/[\s\n]+/);

    for (i =0; i < array.length; i++){
        printWord(array[i],i,1000);
    }

}

$(readBook);

基本上你让动作发生的时间发生在前一个

之后的 X 时间量

这也是可以不使用 jQuery

来完成的事情
 function printWord(w,i,life) {

    setTimeout(function() {
        document.getElementById("word").innerText = w;
    }, i*life);

 }

function readBook() {
    var array = document.getElementById("offscreen_text").innerText.split(/[\s\n]+/);

    for (i =0; i < array.length; i++){
        printWord(array[i],i,1000);
    }

}

document.addEventListener('DOMContentLoaded', readBook);

一切都在同时发生。我传入索引值 i 以乘以 1000ms.

<!DOCTYPE html>
<html>
<head>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
</head>
<body onload="readBook()">
<div id="word"></div>
<div id="offscreen_text">hi hello bye goodbye this is a test with some random text</div>
<div id="sentence">This is some sentence that has the word is.</div>
<script>
    function printWord(w,i) {
    setTimeout(function() {
        $("#word").text(w);
        }, 1000*i);

     }

function readBook() {
    var array = $("#offscreen_text").text().toString().split(/[\s\n]+/);
    for (i =0; i < array.length; i++){
        printWord(array[i],i);
    }

}
</script>
</body>
</html>