2016-08-01 76 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

相關問題