for循环中的setTimeout没有执行传递给它的函数

时间:2016-08-01 20:50:52

标签: javascript for-loop settimeout

我试图制作一个"控制台打字效果"使用js,并在下一个函数中我获取元素的文本,然后我使用" for"用于切片文本并在内部粘贴延迟的循环。

调试chrome中的代码后,我可以看到javascript没有运行setTimeout ......它只是忽略它。

function type() {
    var text = document.querySelector('.console-effect').textContent;
    for (var i = 0; i <= text.length; i++) {
        setTimeout(function() {
            document.querySelector('.console-effect').textContent = text.substr(0, i)
        }, 50);
    }
}
type();

7 个答案:

答案 0 :(得分:3)

您的setTimeout都在同一时间执行,因为for循环不等待它们在每次迭代时执行。您必须使用50*i等值来延迟每个超时。

然后,为了在这种情况下保留i的值,您需要使用闭包。否则,当你的超时结束时,循环将结束,i将是所有这些循环的最终值。

&#13;
&#13;
var text = document.querySelector('.console-effect').textContent;

for (var i = 0; i <= text.length; i++) {
  (function(i) {  
    setTimeout(function() {
      document.querySelector('.console-effect').textContent = text.substr(0, i);
    }, 50*i);
  })(i);
}
&#13;
body{background: #333;}
.console-effect{color: #0f0; font-family: monospace; font-size: 2em;}
&#13;
<div class="console-effect">This is some example text</div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

在Javascript中使用循环中的函数不是一个好主意,我有很糟糕的经验

这样做的代码应该可以正常工作:

function type() {
    var text = document.querySelector('.console-effect').textContent;
    var loopFunc = function(i) {
        return function() {
            document.querySelector('.console-effect').textContent = text.substr(0, i)
        };
    };
    for (var i = 0; i <= text.length; i++) {
        setTimeout(loopFunc(i), 50);
    }
}
type();

答案 2 :(得分:1)

我不想相信@blex,但他对范围是正确的。他做出的两点都是正确的,但封闭让我震惊。我怎么从来没有遇到过这种情况而被迫在以前解决问题呢?

所以这里的想法是,不是在开始时安排十几个调用你的函数,而是只安排下一个调用。在调用之后,它会看到是否需要安排下一个。

&#13;
&#13;
function type() {
    var text = document.querySelector('.console-effect').textContent;
    var i = 0;
    var typeNext = function() {
        ++i;
        document.querySelector('.console-effect').textContent = text.substr(0, i);
        if(i < text.length) {
            setTimeout(typeNext, 50);
        }
    }
    setTimeout(typeNext, 50);
}
type();
&#13;
<span class="console-effect">This is a test</span>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

var text = document.querySelector('.console-effect').textContent;
var index = 0;
setInterval(function(){
     document.querySelector('.console-effect').textContent = text.substr(0, index);
     if(index == text.lenght){
         clearInterval(this);
     }
index++;
},1000);

答案 4 :(得分:0)

做这样的事情。

function type() {
    var text = document.querySelector('.console-effect').textContent;
    document.querySelector('.console-effect').textContent = '';//clear content
    for (var i = 0; i <= text.length; i++) {
        setTimeout(function(j) {
            document.querySelector('.console-effect').textContent += text[j];// or .charAt(j)
        }, 50 * i, i);
        // 50 * i sets timeout for each iteration
        // i (3rd arg) passes to the inner function
    }
}
type();

更好的版本。

function type(text) {
    var textObj = document.querySelector('.console-effect');
    for (var i = 0; i <= text.length; i++) {
        setTimeout(function(ch) {
            textObj.textContent += ch;
        }, 50 * i, text[i]);
        // 50 * i sets timeout for each iteration
        // i (3rd arg) passes to the inner function
    }
}
type('.console-effect');

答案 5 :(得分:0)

没有50 * i的解决方案,也看看css效果。问题是setTimeout是异步执行的(&#39;控制流&#39;不等待那些50ms),所以它们一起被激活,值i = text.length(如果你的文字足够小)

<p class="console-effect">console effects</p>
<script>
function type() {
        var i=0;
        var t = document.querySelector('.console-effect').textContent;
        var fn = setInterval(function() {
            print_text(++i,t,fn)
        }, 500);
}
function print_text(i,t,fn){
    if(i <= t.length){
                document.querySelector('.console-effect').textContent = t.substr(0, i)
    } else clearInterval(fn)
}
type();

</script>
<style>
@-webkit-keyframes blinker {  
  from { opacity: 1.0; }
  to { opacity: 0.0; }
}
.console-effect:after{
    content:'_';
    text-decoration: blink;
    -webkit-animation-name: blinker;
    -webkit-animation-duration: 0.2s;
    -webkit-animation-iteration-count:infinite;
    -webkit-animation-timing-function:ease-in-out;
    -webkit-animation-direction: alternate;
    }
</style>

答案 6 :(得分:-2)

setTimeout只运行一次(在你的情况下延迟50ms后)。

为此,您应该使用setInterval