T3 - 構建大型網站的JavaScript框架
T3是一個JavaScript UI Framework,主要的功能是讓程式碼更結構化。如果網站內的程式碼很雜亂的話,很適合用來整理散落在各處的程式碼(尤其是針對年紀大需要翻新的大型網站)。而整理方式就是將程式碼分成幾個部份:Application、Module、Serveice、Behavior等來處理。頁面UI整理成Module,Module彼此共用的方法或事件整理成Behavior,而非UI邏輯且多個Module會共用的部份(例如:與Server端溝通取資料)則抽出來成為Service。
Module
將頁面功能切成模組(Module)來運作,如果頁面無法切成多個模組就將整個頁面視為一個模組。模組的事件有以下幾種:Message Handling、Behavior、Event Handlers(例如:onclick)。如下:頁面上的模組「test-module」,可能需要針對其他模組的反應來做出回應,因此有Message Handling;不同模組但有重覆的事情要做,則可用Behavior;模組內的事件處理可使用onclick等;非UI邏輯的部份丟給Service即可。
HTML
JS
Box.Application.addModule('test-module', function(context) {
return {
messages: ['statechanged', 'statecompleted'],
onmessage: function(name, data) {
switch(name) {
case 'statechanged':
console.log('statechanged');
break;
case 'searchcomplete':
console.log('statecompleted: ' + data.numResults + ' tasks completed.');
break;
}
},
behaviors: ['getInfo'],
init: function(){
console.log('module init');
},
onclick: function(event, element, elementType){
console.log('click');
context.getService('connectSomething').connect();
}
}
});
Service
Module與Behavior負責處理UI,而非UI的部份則交給Service。Service可當成一個共用的介面,讓不同的Module和Behavior來共同呼叫。例如:使用ajax取資料。如下範例,「getInfo」這個Service負責與Server端溝通取資料,我們呼叫這個Service的method「getSearchResultByKeyword」,並將結果回傳給Behavior「getSearchResult」。Box.Application.addService('getInfo', function(application) {
return {
getSearchResultByKeyword: function(query) {
$.ajax({
url: '/getSearchResult',
type: 'post',
data: {
query: query
},
dataType: 'json',
success: function (response) {
return response.data;
},
error: function (xhr) {
alert('噢噢!發生錯誤了!請重新再試一次~');
}
});
}
};
});
Box.Application.addBehavior('getSearchResult', function(context) {
var query = "日式料理";
return {
init: function() {
var data = context.getService('getInfo').getSearchResultByKeyword(query);
console.log(data);
}
};
});
Box.Application.init();
Behavior
不同模組但有重覆的事情要做,則可在模組中使用Behavior。Box.Application.addModule('module-test-1', function(context) {
return {
behaviors: ['element-button'],
init: function(){
console.log('init');
}
}
});
Box.Application.addModule('module-test-2', function(context) {
return {
behaviors: ['element-button'],
init: function(){
console.log('init');
}
}
});
Box.Application.addBehavior('element-button', function(context) {
return {
init: function() {
console.log('add behavior');
context.getService('connectSomething').connect();
}
};
});
Box.Application.addService('connectSomething', function(application) {
return {
connect: function() {
console.log('connect something...');
}
};
});
Box.Application.init();
DOMEventDelegate
委派,範例如下。HTML
JS
Box.Application.addModule('module-domeventdelegate', function(context) {
var element = context.getElement();
var delegate = new Box.DOMEventDelegate(element, {
onclick: function(event) {
console.log('DOMEventDelegate: ' + event.type);
}
});
return {
init: function(){
var element = context.getElement();
delegate.attachEvents(); //DOMEventDelegate
},
onclick: function(event, element, elementType){
console.log('click!');
}
}
});
Box.Application.init();
Context
broadcast
模組訂閱事件,事件發生時會通知模組。可用在網站的訊息中心等。HTML
1
2
JS
Box.Application.addModule('module-broadcast-1', function(context) {
return {
messages: ['broadcast-a', 'broadcast-b'],
onmessage: function(name, data) {
switch(name) {
case 'broadcast-a':
console.log('broadcast-a');
Box.Application.broadcast('broadcast-b');
break;
case 'broadcast-b':
console.log('broadcast-b');
break;
}
}
}
});
Box.Application.addModule('module-broadcast-2', function(context) {
return {
messages: ['broadcast-a', 'broadcast-c'],
onmessage: function(name, data) {
switch(name) {
case 'broadcast-a':
console.log('broadcast-a');
break;
case 'broadcast-c':
console.log('broadcast-c');
break;
}
},
}
});
Box.Application.init();
Box.Application.broadcast('broadcast-a');
Box.Application.broadcast('broadcast-c');
getGlobal
取得window物件。HTML
test
JS
Box.Application.addModule('module-test', function(context) {
return {
init: function(){
var navigator = context.getGlobal('navigator');
console.log(window.navigator.userAgent === navigator.userAgent);
}
}
});
Box.Application.init();
getGlobalConfig
取得Box.Application.init
中的設定物件。HTML
test
JS
Box.Application.addModule('module-test', function(context) {
return {
init: function(){
console.log(context.getGlobalConfig('userName'));
}
}
});
Box.Application.init({
userName: 'Bob'
});
以上只列出目前比較常用的部份,T3的文件寫得很詳細,有興趣的話可以看一下。
我也將之前參加駭客松的作品吃什麼,どっち部份改版使用T3實作。
以上的程式碼都會放在Github上(含簡單的TodoList),如果有什麼建議或想法都歡迎聊聊。
由於部落格搬家了,因此在新落格也放了一份,未來若有增刪會在這裡更新-T3 - 構建大型網站的 JavaScript 框架。
留言