2016-08-01 65 views
0

我试图用js做一个“控制台打字效果”,并且在下一个功能中我带一个元素的文本,然后使用“for”循环切割文本并在延迟内粘贴。setTimeout在一个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(); 
+1

你说的 “它根本不理会” 的setTimeout是什么意思?你有没有把调试'console.log()'放在那里,看看匿名函数是否在运行?无论如何,我可以立即看到你将遇到问题。您需要为循环的每次迭代“关闭”“i”的值,否则您的代码将无法按预期运行。尝试在闭包中封装'setTimeout()'调用。 – jered

回答

3

setTimeout s的所有在同一时间执行,因为for循环不会等待他们在每个迭代执行。您必须使用诸如50*i之类的值来延迟每个超时。

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

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); 
 
}
body{background: #333;} 
 
.console-effect{color: #0f0; font-family: monospace; font-size: 2em;}
<div class="console-effect">This is some example text</div>

+0

谢谢,我明白了为什么我得到了错误。唯一我没有得到的是为什么我要在setTimeout周围使用闭包?我的意思是我读了你的答案,但我仍然不太明白:/ –

+1

@ShockE。这里有两个例子可以帮助你理解'i'发生了什么。一个没有闭包:https://jsfiddle.net/zyLozkvp/正如你所看到的,一旦循环结束,'i'在全局范围内等于'11'。还有一个关闭:https://jsfiddle.net/0L3oou1s/。这一次,当你有一个闭包(函数)时,你正在创建一个新的范围,其中'i'是一个全新的变量,在它自己的范围内。这是否更清晰? – blex

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

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

为此,你应该使用的setInterval

+0

setInterval永远循环。 –

+0

不完全 - 你可以根据需要设置多少个'setTimeout',它们被放在彼此独立的堆栈上。 – jered

+0

var index = 0; 的setInterval(函数(){ \t的console.log( '学习JS') \t如果(索引== 10){ \t \t clearInterval(本); \t} 索引++;} ,1000); –

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); 
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'); 
0

没有50 * i的解决方案,看看css的效果。你的问题是setTimeout的是异步执行的(即“控制流”不会等待那些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> 
1

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

因此,这里的想法是,不是在开始时为您的函数安排十几个调用,而只是安排下一次调用。在这之后,它会查看是否需要安排下一个。

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();
<span class="console-effect">This is a test</span>

+0

你介意解释一下type()函数结尾的setTimeout是做什么的?如果我明白,它第一次调用typeNext()? –

+0

@ShockE。那是对的。声明函数后,我延迟50ms然后调用它。然后,在方法结束时,我确定是否有必要延迟并再次调用。 – Nate

相关问题