JavaScript Timer實現 (原)

前言:最近開始接觸flex,比起javascript,感覺as3的Timer類甚是強大。而javascript只有裸體的setTimeout,setInternval。要實現稍微複雜一點的功能,稍微沒有底子的程序員就會把代碼寫的很亂。

ok,不廢話了,實現一個javascript的Timer吧

比起as3的Timer類,功能上略有改動

timer2.src.js

/**
* Timer 模型
*
* @author rainsilence
* @version 2.0
*/
(function() {

/**
* TimerEvent constructor 構造器
*
* @param type 事件類型
* @param bubbles 是否毛票
* @param cancelable 是否可取消
*/
TimerEvent = function(type, bubbles, cancelable) {
this.type = type;
this.bubbles = bubbles;
this.cancelable = cancelable;
};

/**
* Event 時間事件聲明
*
* @event TIMER
* @event TIMER_COMPLETE
*/
extend(TimerEvent, {
TIMER : "timer",
TIMER_COMPLETE : "timerComplete"
});

/**
* Event 方法
*
* @method toString
*/
extend(TimerEvent.prototype, {
toString : function() {
return "[TimerEvent type=" + this.type +
" bubbles=" + this.bubbles +
" cancelable=" + this.cancelable +"]";
}
});

/**
* Extend 擴展類,對象的屬性或者方法
*
* @param target 目標對象
* @param methods 這裏改成param也許更合適,表示承載着對象,方法的對象,用於target的擴展
*/
function extend(target, methods) {

if (!target) {
target = {};
}

for (var prop in methods) {
target[prop] = methods[prop];
}

return target;
}

/**
* Timer 構造器
*
* @param delay 延時多少時間執行方法句柄
* @param repeatCount 重複多少次,如果不設置,代表重複無限次
*/
Timer = function(delay, repeatCount) {
var listenerMap = {};
listenerMap[TimerEvent.TIMER] = [];
listenerMap[TimerEvent.TIMER_COMPLETE] = [];

extend(this, {
currentCount : 0,
running : false,
delay : delay,
repeatCount : repeatCount,
// true:Interval,false:Timeout
repeatType : repeatCount == null || repeatCount < 1 ? true : false,
handler : listenerMap,
timerId : 0,
isCompleted : false
});
};

// 事件對象初始化(這部分未實現)
var timerEvent = new TimerEvent(TimerEvent.TIMER, false, false);
var timerCompleteEvent = new TimerEvent(TimerEvent.TIMER_COMPLETE, false, false);

/**
* Timer 計時器方法
*
* @method addEventListener 增加一個方法句柄(前兩個參數必須,後一個參數可選)
* @method removeEventListener 移除一個方法句柄
* @method start 開始計時器
* @method stop 結束計時器
* @method reset 重置計時器
*/
extend(Timer.prototype, {

addEventListener : function(type, listener, useCapture) {
if (type == TimerEvent.TIMER || type == TimerEvent.TIMER_COMPLETE) {

if (!listener) {
alert("Listener is null");
}

if (useCapture == true) {
this.handler[type].splice(0, 0, [listener]);
} else {
this.handler[type].push(listener);
}
}
},

removeEventListener : function(type, listener) {
if (type == TimerEvent.TIMER || type == TimerEvent.TIMER_COMPLETE) {

if (!listener) {
this.handler[type] = [];
} else {

var listeners = this.handler[type];

for (var index = 0; index < listeners.length; index++) {
if (listeners[index] == listener) {
listeners.splice(index, 1);
break;
}
}
}
}
},

start : function() {

var timerThis = this;

if (this.running == true || this.isCompleted) {
return;
}

if (this.handler[TimerEvent.TIMER].length == 0 &&
this.handler[TimerEvent.TIMER_COMPLETE].length == 0) {
alert("No Function");
return;
}

if (this.repeatType) {
this.timerId = setInterval(function() {
dispachListener(timerThis.handler[TimerEvent.TIMER], timerEvent);
timerThis.currentCount++;
}, this.delay);
} else {
this.timerId = setTimeout(function() {delayExecute(timerThis.handler[TimerEvent.TIMER]);}, this.delay);
}

this.running = true;

function delayExecute(listeners) {
dispachListener(listeners, timerEvent);
timerThis.currentCount++;

if (timerThis.currentCount < timerThis.repeatCount) {
if (timerThis.running) {
timerThis.timerId = setTimeout(function() {delayExecute(listeners);}, timerThis.delay);
}
} else {
timerThis.running = false;
}
if (timerThis.running == false) {
if (!timerThis.isCompleted) {
dispachListener(timerThis.handler[TimerEvent.TIMER_COMPLETE], timerCompleteEvent);
}
timerThis.isCompleted = true;
}
}

function dispachListener(listeners, event) {
for (var prop in listeners) {
listeners[prop](event);
}
}
},
stop : function() {
this.running = false;

if (this.timerId == null) {
return;
}

if (this.repeatType) {
clearInterval(this.timerId);
} else {
clearTimeout(this.timerId);
}
if (!this.isCompleted) {

var listeners = this.handler[TimerEvent.TIMER_COMPLETE];

for (var prop in listeners) {
listeners[prop](timerCompleteEvent);
}
}
this.isCompleted = true;
},

reset : function() {
this.currentCount = 0;
this.isCompleted = false;
}
});
})();



接下來測試吧,大家見過新浪網上的滾動顯示嗎?用setTimeout寫的,真叫牛叉。。。。。。換成Timer重構,簡單易懂

timerTest.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j">
<title>Insert title here</title>
<style type="text/css">
.rowLine {
width: 400px;
height: 80px;
border-bottom-style: solid;
border-width: 1px;
}

.barList {
border-style: solid;
border-width: 1px;
width:400px;
height: 80px;
overflow: hidden;
}
</style>
<script type="text/javascript" src="js/timer2.src.js"></script>
<script type="text/javascript">
<!--
var timer = new Timer(50);
var globalTimer = new Timer(10000);
var bList;
function init() {
bList = document.getElementById("barList");

timer.addEventListener(TimerEvent.TIMER, calTime);
timer.start();
globalTimer.addEventListener(TimerEvent.TIMER, controlTime);
globalTimer.start();
}
function controlTime() {
if (!timer.running) {
timer.reset();
timer.start();
}
}

function calTime() {

bList.scrollTop += 1;
if (bList.scrollTop > 80) {
timer.stop();
var barNode = bList.firstChild;
if (barNode.nodeType == 3) {
bList.appendChild(barNode);
bList.appendChild(bList.getElementsByTagName("div")[0]);
} else {
bList.appendChild(barNode);
}

bList.scrollTop = 0;
}
}

window.onload = init;
// -->
</script>
</head>
<body>
<div class="barList" id="barList">
<div class="rowLine" style="background-color: red" mce_style="background-color: red">1</div>
<div class="rowLine" style="background-color: pink" mce_style="background-color: pink">2</div>
<div class="rowLine" style="background-color: blue" mce_style="background-color: blue">3</div>
<div class="rowLine" style="background-color: gray" mce_style="background-color: gray">4</div>
</div>
</body>
</html>



addEventListener的useCapture參數本爲捕獲階段觸發之意,現在改成如果true,則在其他句柄之前觸發,如果false,則在其他句柄之後觸發。

後記:

現在貌似大家比較流行評論說明書的用法。。。比如struts+spring+hibernate。而忽略了編程的實質。希望大家多看源碼,多討論源碼,那樣纔會有所謂的思想。否則人家今天用這個framework,明天換了。你又要從頭開始了。
發佈了12 篇原創文章 · 獲贊 1 · 訪問量 2535
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章