前言:最近開始接觸flex,比起javascript,感覺as3的Timer類甚是強大。而javascript只有裸體的setTimeout,setInternval。要實現稍微複雜一點的功能,稍微沒有底子的程式員就會把代碼寫的很亂。
ok,不廢話了,實現一個javascript的Timer吧
比起as3的Timer類,功能上略有改動
timer2.src.js
/**<br /> * Timer 模型<br /> *<br /> * @author rainsilence<br /> * @version 2.0<br /> */<br />(function() {</p><p>/**<br /> * TimerEvent constructor 構造器<br /> *<br /> * @param type 事件類型<br /> * @param bubbles 是否毛票<br /> * @param cancelable 是否可取消<br /> */<br />TimerEvent = function(type, bubbles, cancelable) {<br />this.type = type;<br />this.bubbles = bubbles;<br />this.cancelable = cancelable;<br />};</p><p>/**<br /> * Event 時間事件聲明<br /> *<br /> * @event TIMER<br /> * @event TIMER_COMPLETE<br /> */<br />extend(TimerEvent, {<br />TIMER : "timer",<br />TIMER_COMPLETE : "timerComplete"<br />});</p><p>/**<br /> * Event 方法<br /> *<br /> * @method toString<br /> */<br />extend(TimerEvent.prototype, {<br />toString : function() {<br />return "[TimerEvent type=" + this.type +<br />" bubbles=" + this.bubbles +<br />" cancelable=" + this.cancelable +"]";<br />}<br />});</p><p>/**<br /> * Extend 擴充類,對象的屬性或者方法<br /> *<br /> * @param target 目標對象<br /> * @param methods 這裡改成param也許更合適,表示承載著對象,方法的對象,用於target的擴充<br /> */<br />function extend(target, methods) {</p><p>if (!target) {<br />target = {};<br />}</p><p>for (var prop in methods) {<br />target[prop] = methods[prop];<br />}</p><p>return target;<br />}</p><p>/**<br /> * Timer 構造器<br /> *<br /> * @param delay 延時多少時間執行方法控制代碼<br /> * @param repeatCount 重複多少次,如果不設定,代表重複無限次<br /> */<br />Timer = function(delay, repeatCount) {<br />var listenerMap = {};<br />listenerMap[TimerEvent.TIMER] = [];<br />listenerMap[TimerEvent.TIMER_COMPLETE] = [];</p><p>extend(this, {<br />currentCount : 0,<br />running : false,<br />delay : delay,<br />repeatCount : repeatCount,<br />// true:Interval,false:Timeout<br />repeatType : repeatCount == null || repeatCount < 1 ? true : false,<br />handler : listenerMap,<br />timerId : 0,<br />isCompleted : false<br />});<br />};</p><p> // 事件對象初始化(這部分未實現)<br />var timerEvent = new TimerEvent(TimerEvent.TIMER, false, false);<br />var timerCompleteEvent = new TimerEvent(TimerEvent.TIMER_COMPLETE, false, false);</p><p>/**<br /> * Timer 計時器方法<br /> *<br /> * @method addEventListener 增加一個方法控制代碼(前兩個參數必須,後一個參數可選)<br /> * @method removeEventListener 移除一個方法控制代碼<br /> * @method start 開始計時器<br /> * @method stop 結束計時器<br /> * @method reset 重設計時器<br /> */<br />extend(Timer.prototype, {</p><p>addEventListener : function(type, listener, useCapture) {<br />if (type == TimerEvent.TIMER || type == TimerEvent.TIMER_COMPLETE) {</p><p>if (!listener) {<br />alert("Listener is null");<br />}</p><p>if (useCapture == true) {<br />this.handler[type].splice(0, 0, [listener]);<br />} else {<br />this.handler[type].push(listener);<br />}<br />}<br />},</p><p>removeEventListener : function(type, listener) {<br />if (type == TimerEvent.TIMER || type == TimerEvent.TIMER_COMPLETE) {</p><p>if (!listener) {<br />this.handler[type] = [];<br />} else {</p><p>var listeners = this.handler[type];</p><p>for (var index = 0; index < listeners.length; index++) {<br />if (listeners[index] == listener) {<br />listeners.splice(index, 0);<br />break;<br />}<br />}<br />}<br />}<br />},</p><p>start : function() {</p><p>var timerThis = this;</p><p>if (this.running == true || this.isCompleted) {<br />return;<br />}</p><p>if (this.handler[TimerEvent.TIMER].length == 0 &&<br />this.handler[TimerEvent.TIMER_COMPLETE].length == 0) {<br />alert("No Function");<br />return;<br />}</p><p>if (this.repeatType) {<br />this.timerId = setInterval(function() {<br />dispachListener(timerThis.handler[TimerEvent.TIMER], timerEvent);<br />timerThis.currentCount++;<br />}, this.delay);<br />} else {<br />this.timerId = setTimeout(function() {delayExecute(timerThis.handler[TimerEvent.TIMER]);}, this.delay);<br />}</p><p>this.running = true;</p><p>function delayExecute(listeners) {<br />dispachListener(listeners, timerEvent);<br />timerThis.currentCount++;</p><p>if (timerThis.currentCount < timerThis.repeatCount) {<br />if (timerThis.running) {<br />timerThis.timerId = setTimeout(function() {delayExecute(listeners);}, timerThis.delay);<br />}<br />} else {<br />timerThis.running = false;<br />}<br />if (timerThis.running == false) {<br />if (!timerThis.isCompleted) {<br />dispachListener(timerThis.handler[TimerEvent.TIMER_COMPLETE], timerCompleteEvent);<br />}<br />timerThis.isCompleted = true;<br />}<br />}</p><p>function dispachListener(listeners, event) {<br />for (var prop in listeners) {<br />listeners[prop](event);<br />}<br />}<br />},<br />stop : function() {<br />this.running = false;</p><p>if (this.timerId == null) {<br />return;<br />}</p><p>if (this.repeatType) {<br />clearInterval(this.timerId);<br />} else {<br />clearTimeout(this.timerId);<br />}<br />if (!this.isCompleted) {</p><p>var listeners = this.handler[TimerEvent.TIMER_COMPLETE];</p><p>for (var prop in listeners) {<br />listeners[prop](timerCompleteEvent);<br />}<br />}<br />this.isCompleted = true;<br />},</p><p>reset : function() {<br />this.currentCount = 0;<br />this.isCompleted = false;<br />}<br />});<br />})();
接下來測試吧,大家見過新浪網上的滾動顯示嗎?用setTimeout寫的,真叫牛叉。。。。。。換成Timer重構,簡單易懂
timerTest.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br /><html><br /><head><br /><meta http-equiv="Content-Type" content="text/html; charset=windows-31j"><br /><title>Insert title here</title><br /><mce:style type="text/css"><!--<br />.rowLine {<br />width: 400px;<br />height: 80px;<br />border-bottom-style: solid;<br />border-width: 1px;<br />}</p><p>.barList {<br />border-style: solid;<br />border-width: 1px;<br />width:400px;<br />height: 80px;<br />overflow: hidden;<br />}<br />--></mce:style><style type="text/css" mce_bogus="1">.rowLine {<br />width: 400px;<br />height: 80px;<br />border-bottom-style: solid;<br />border-width: 1px;<br />}</p><p>.barList {<br />border-style: solid;<br />border-width: 1px;<br />width:400px;<br />height: 80px;<br />overflow: hidden;<br />}</style><br /><mce:script type="text/javascript" src="js/timer2.src.js" mce_src="js/timer2.src.js"></mce:script><br /><mce:script type="text/javascript"><!--<br />var timer = new Timer(50);<br />var globalTimer = new Timer(10000);<br />var bList;<br />function init() {<br />bList = document.getElementById("barList");</p><p>timer.addEventListener(TimerEvent.TIMER, calTime);<br />timer.start();<br />globalTimer.addEventListener(TimerEvent.TIMER, controlTime);<br />globalTimer.start();<br />}<br />function controlTime() {<br />if (!timer.running) {<br />timer.reset();<br />timer.start();<br />}<br />}</p><p>function calTime() {</p><p>bList.scrollTop += 1;<br />if (bList.scrollTop > 80) {<br />timer.stop();<br />var barNode = bList.firstChild;<br />if (barNode.nodeType == 3) {<br />bList.appendChild(barNode);<br />bList.appendChild(bList.getElementsByTagName("div")[0]);<br />} else {<br />bList.appendChild(barNode);<br />}</p><p>bList.scrollTop = 0;<br />}<br />}</p><p>window.onload = init;<br />// --></mce:script><br /></head><br /><body><br /><div class="barList" id="barList"><br /><div class="rowLine" style="background-color: red" mce_style="background-color: red">1</div><br /><div class="rowLine" style="background-color: pink" mce_style="background-color: pink">2</div><br /><div class="rowLine" style="background-color: blue" mce_style="background-color: blue">3</div><br /><div class="rowLine" style="background-color: gray" mce_style="background-color: gray">4</div><br /></div><br /></body><br /></html>
addEventListener的useCapture參數本為捕獲階段觸發之意,現在改成如果true,則在其他控制代碼之前觸發,如果false,則在其他控制代碼之後觸發。
後記:
現在貌似大家比較流行評論說明書的用法。。。比如struts+spring+hibernate。而忽略了編程的實質。希望大家多看源碼,多討論源碼,那樣才會有所謂的思想。否則人家今天用這個framework,明天換了。你又要從頭開始了。