定時器javascript
一、setTimeoutcss
這個方法用於在指定的毫秒數以後執行某個函數,返回定時器的句柄html
混合的 setTimeout()
方法設置一個定時器,該定時器在定時器到期後執行一個函數或指定的一段代碼。java
let timeoutID = window.setTimeout(func[, delay, param1, param2, ...]); let timeoutID = scope.setTimeout(code[, delay]); let timeoutID = window.setTimeout(function, milliseconds);
說明:node
timeoutID
是該延時操做的數字ID, 此ID隨後能夠用來做爲window.clearTimeout方法的參數.func
是你想要在delay
毫秒以後執行的函數.code
在第二種語法,是指你想要在delay
毫秒以後執行的代碼字符串 (使用該語法是不推薦的, 不推薦的緣由和eval()同樣)delay
是延遲的毫秒數 (一秒等於1000毫秒),函數的調用會在該延遲以後發生。若是省略該參數,delay取默認值0。實際的延遲時間可能會比 delay 值長,緣由請查看下面的備註。須要注意的是,IE9 及更早的 IE 瀏覽器不支持第一種語法中向延遲函數傳遞額外參數的功能。若是你想要在IE中達到一樣的功能,你必須使用一種兼容代碼api
備註: 在Gecko 13以前 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), Gecko會給延遲函數傳遞一個額外的參數,該參數代表了這次延遲操做實際延遲的毫秒數.如今,這個非標準的參數已經不存在了.瀏覽器
下文的例子在網頁中設置了兩個簡單的按鈕,以觸發 setTimeout 和 clearTimeout 方法:按下第一個按鈕會在 2s 後顯示一個警告對話框,並將這次 setTimeout 的延時 ID 保存起來。按下第二個按鈕能夠取消此次延時調用行爲。app
<p>Live Example</p>
<button onclick="delayedAlert();">Show an alert box after two seconds</button>
<p></p>
<button onclick="clearAlert();">Cancel alert before it happens</button>
var timeoutID; function delayedAlert() { timeoutID = window.setTimeout(slowAlert, 2000); } function slowAlert() { alert("That was really slow!"); } function clearAlert() { window.clearTimeout(timeoutID); }
若是你須要向你的回調函數內傳遞一個參數, 並且還須要兼容IE9及之前的版本, 因爲IE不支持傳遞額外的參數 (setTimeout()
或者 setInterval()
都不能夠) ,但你能夠引入下面的兼容代碼.該代碼能讓IE也支持符合HTML5標準的定時器函數.函數
/*\ |*| |*| IE-specific polyfill which enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax). |*| |*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/
if (document.all && !window.setTimeout.isPolyfill) { var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setTimeout.isPolyfill = true; } if (document.all && !window.setInterval.isPolyfill) { var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setInterval.isPolyfill = true; }
若是你須要單獨的針對IE9及以前瀏覽器的 hack 寫法,你可使用 JavaScript 條件註釋:動畫
/*@cc_on // conditional IE < 9 only fix @if (@_jscript_version <= 9) (function(f){ window.setTimeout =f(window.setTimeout); window.setInterval =f(window.setInterval); })(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c.apply(this,a)},t)}}); @end @*/
或者使用更加清晰的 IE HTML 條件註釋:
<!--[if lte IE 9]><script> (function(f){ window.setTimeout =f(window.setTimeout); window.setInterval =f(window.setInterval); })(function(f){return function(c,t){ var a=[].slice.call(arguments,2); return f(function(){c.apply(this,a)},t)} }); </script><![endif]-->
另外一種方法是使用匿名函數包裹你的回調函數,這種方式要消耗更多資源:
var intervalID = setTimeout(function() { myFunc("one", "two", "three"); }, 1000);
此外,也可以使用 function's bind:
setTimeout(function(arg1){}.bind(undefined, 10), 1000);
this
"的問題當你向 setTimeout()
(或者其餘函數也行)傳遞一個函數時,該函數中的this
會指向一個錯誤的值
.
由
setTimeout()
調用的代碼運行在與所在函數
徹底分離的執行環境上. 這會致使,這些代碼中包含的 this
關鍵字會指向 window
(或全局
)對象,這和所指望的
this
的值是不同的
.
查看下面的例子
:
myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1,5 seconds // let's try to pass the 'this' object
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error
正如你所看到的同樣,咱們沒有任何方法將this
對象傳遞給回調函數
.
一個可用的解決 "this
" 問題的方法是使用兩個非原生的setTimeout()
和 setInterval()
全局函數代替原生的.該非原生的函數經過使用Function.prototype.call
方法激活了正確的做用域.下面的代碼顯示了應該如何替換:
// Enable the passage of the 'this' object through the JavaScript timers
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); }; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); };
備註: 這兩個替換也讓 IE支持了符合 HTML5 標準的定時器函數。因此也能做爲一個 polyfills
新特性檢測:
myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2,5 seconds
針對這個問題並無原生的解決方案。
注:JavaScript 1.8.5 引入了 Function.prototype.bind()
方法,該方法容許顯式地指定函數調用時 this 所指向的值 。該方法能夠幫助你解決 this 指向不肯定的問題。
使用bind的例子:
myArray = ["zero", "one", "two"]; myBoundMethod = (function (sProperty) { console.log(arguments.length > 0 ? this[sProperty] : this); }).bind(myArray); myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds
你可使用 window.clearTimeout()
來取消延遲操做。若是你但願你的代碼被重複的調用 (好比每 N 毫秒一次),考慮使用 window.setInterval()
。
記住這一點:只有當調用setTimeout()的線程中止後,函數或代碼段才能繼續執行。
向setTimeout()
傳遞一個字符串而不是函數會遭受到與使用
eval
同樣的風險
.
// 推薦
window.setTimeout(function() { alert("Hello World!"); }, 500); // 不推薦
window.setTimeout("alert(\"Hello World!\");", 500);
字符串會在全局做用域內被解釋執行,因此當setTimeout()
函數執行完畢後,字符串中的變量不可用.
二、 setInterval
這個方法用於循環地執行某個函數,返回定時器的句柄
var intervalID = window.setInterval(func, delay[, param1, param2, ...]); var intervalID = window.setInterval(code, delay);
參數
intervalID
是此重複操做的惟一辨識符,能夠做爲參數傳給clearInterval()
。func
是你想要重複調用的函數。code
是另外一種語法的應用,是指你想要重複執行的一段字符串構成的代碼(使用該語法是不推薦的,不推薦的緣由和eval()同樣)。delay
是每次延遲的毫秒數 (一秒等於1000毫秒),函數的每次調用會在該延遲以後發生。和setTimeout同樣,實際的延遲時間可能會稍長一點。須要注意的是,IE不支持第一種語法中向延遲函數傳遞額外參數的功能.若是你想要在IE中達到一樣的功能,你必須使用一種兼容代碼
備註: 在Gecko 13以前 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), Gecko會給延遲函數傳遞一個額外的參數,該參數代表了這次延遲操做實際延遲的毫秒數。如今,這個非標準的參數已經不存在了。
重複調用一個函數或執行一個代碼段,以固定的時間延遲在每次調用之間。返回一個 intervalID。
var intervalID = window.setInterval(animate, 500);
下面的例子裏會每隔一秒就調用函數flashtext()
一次,直至你經過按下Stop按鈕來清除本次重複操做的惟一辨識符intervalID
。
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>setInterval/clearInterval example</title>
<script type="text/javascript">
var nIntervId; function changeColor() { nIntervId = setInterval(flashText, 500); } function flashText() { var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "red" ? "blue" : "red"; } function stopTextColor() { clearInterval(nIntervId); } </script>
</head>
<body onload="changeColor();">
<div id="my_box">
<p>Hello World</p>
</div>
<button onclick="stopTextColor();">Stop</button>
</body>
</html>
下面這個例子經過鍵入、刪除和再次鍵入全部NodeList
中的符合的特定selector的字符,以達到打字機的效果。
<!doctype html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title>JavaScript Typewriter - MDN Example</title> <script type="text/javascript"> function Typewriter (sSelector, nRate) { function clean () { clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; } function scroll (oSheet, nPos, bEraseAndStop) { if (!oSheet.hasOwnProperty("parts") || aMap.length < nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap[nPos] < oSheet.parts.length) { oRel = oSheet.parts[aMap[nPos]]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap[nPos]++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets[nIdx], 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts[nChild]); this.parts[nChild] = new Sheet(this.parts[nChild]); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = [], aMap = []; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems[nItem])); /* Uncomment the following line if you have previously hidden your elements via CSS: */ // aItems[nItem].style.visibility = "visible"; } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets[nIdx++], 0, false)); clean(); }; } /* usage: */ var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */ var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */ // oTWExample2.rate = 150; onload = function () { oTWExample1.play(); oTWExample2.play(); }; </script> <style type="text/css"> span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline; } #info { width: 180px; height: 150px; float: right; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px; /* visibility: hidden; */ } </style> </head> <body> <p id="copyleft" style="font-style: italic; font-size: 12px; text-align: center;">CopyLeft 2012 by <a href="https://developer.mozilla.org/" target="_blank">Mozilla Developer Network</a></p> <p id="controls" style="text-align: center;">[ <span class="intLink" onclick="oTWExample1.play();">Play</span> | <span class="intLink" onclick="oTWExample1.pause();">Pause</span>
| <span class="intLink" onclick="oTWExample1.terminate();">Terminate</span> ]</p> <div id="info"> Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque.
Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt. </div> <h1>JavaScript Typewriter</h1> <div id="article"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna.
Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula
quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas,
velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.</p> <form name="myForm"> <p>Phasellus ac nisl lorem: <input type="text" name="email" /><br /> <textarea name="comment" style="width: 400px; height: 200px;">
Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque
dapibus tellus ut ipsum aliquam eu auctor dui vehicula. Quisque ultrices laoreet erat, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque
urna vitae nibh tristique varius consequat neque luctus. Integer ornare, erat a porta tempus, velit justo fermentum elit, a fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa.
Praesent vitae eros erat, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus a turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.</textarea></p> <p><input type="submit" value="Send" /> </form> <p>Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis
gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est in quam tempor consequat. Aliquam aliquam
diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum.
Praesent bibStartum condimentum feugiat.</p> <p>Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Pellentesque a nisl eu sem vehicula egestas.</p> </div> </body> </html>
倒計時:
<div class="box">
<span class="h time">12</span>
<span>:</span>
<span class="m time">12</span>
<span>:</span>
<span class="s time">55</span>
</div>
<script>
var div = document.body.children[0]; //全部的span
var spans = div.children; var second = spans[4]; var minutes = spans[2]; console.log(minutes); //每隔1秒鐘修改秒數
setInterval(function(){ // 先獲取舊的數字,自增,從新賦值
var old = parseInt(second.innerText); var m = parseInt(minutes.innerText); old +=1; //以上是秒的邏輯,到分的邏輯
//當秒數大於59,就滿一分鐘,分自增,秒重置
if(old >59){ old = 0; //獲取分的值,自增,從新賦值
m += 1; } //小時的邏輯也是當分超過59,讓小時自增1,分重置
second.innerText = old; minutes.innerText = m; },1000); </script>
簡單動畫效果的實現
<!DOCTYPE html>
<html>
<head lang="zh-CN">
<meta charset="UTF-8">
<title></title>
<style> * { margin: 0; padding: 0;
} #box { width: 100px; height: 100px; background-color: #0a0;
/*margin-left: 500px;*/
/*通常作動畫,都會使用定位,脫標定位 -- 絕對,固定*/ position: absolute; top: 200px; left: 0px;
} .boxw { width: 100px; height: 100px; background: #cccccc; float: left;
}
</style>
</head>
<body>
<input type="button" value="開始運動" id="btn"/>
<div id="box"></div>
<div class="boxw"></div>
<script>
//動畫原理:每隔必定的時間,修改能控制元素位置的屬性,就能達到動起來的效果,當位置到達800的時候停下來
var curerntLeft = 0; var box = document.getElementById("box"); document.getElementById("btn").onclick = function(){ var timerId = setInterval(function(){ //每次獲取當前位置,進行自增,最後從新賦值
var step = 10;//每次移動的步長
curerntLeft += step; box.style.left = curerntLeft + "px"; //判斷當前位置是否大於等於800,若是是,就停下來
if(curerntLeft >= 800){ clearInterval(timerId); } console.log(123456); },20);//人的肉眼通常可識別的間隔爲:0.03秒 = 30毫秒
} </script>
</body>
</html>
回調參數
若是你想經過你的函數傳遞迴一個參數,並且還要兼容IE,因爲IE不支持傳遞額外的參數 (setTimeout()
或者 setInterval()
都不能夠) ,你能夠引入下面的兼容代碼。該代碼能讓IE也支持符合HTML5標準的定時器函數。
/*\ |*| |*| IE-specific polyfill which enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax). |*| |*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/
if (document.all && !window.setTimeout.isPolyfill) { var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setTimeout.isPolyfill = true; } if (document.all && !window.setInterval.isPolyfill) { var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; window.setInterval.isPolyfill = true; }