一年前剛開始做項(xiàng)目的時(shí)候,我對(duì)于前臺(tái)技術(shù)還剛剛?cè)腴T,用jquery寫點(diǎn)小打小鬧的交互效果還是沒(méi)太大問(wèn)題,但是要把所有這些效果干凈,整潔的部署到全站,對(duì)我來(lái)說(shuō)就有點(diǎn)頭疼了.由于網(wǎng)站頁(yè)面雖說(shuō)不是特別多,但也有二三十個(gè),如果每個(gè)頁(yè)面寫一個(gè)單獨(dú)的js文件或者直接把js寫在頁(yè)面內(nèi),是不利于維護(hù)和有損前臺(tái)性能的.按照yahoo的前臺(tái)性能提升建議,應(yīng)該盡量減少js文件個(gè)數(shù).于是我決定想辦法把除了jquery庫(kù)及一些插件之外自寫代碼全部寫到一個(gè)文件之中.雖然可能有時(shí)候某些頁(yè)面載入的js會(huì)有用不到的代碼,但是這樣做對(duì)于一個(gè)中等規(guī)模的網(wǎng)站來(lái)說(shuō)有如下的性能優(yōu)勢(shì):
這樣的部署,可以謂之'輕便'.現(xiàn)在的問(wèn)題就是,如何組織這個(gè)文件,讓其盡量有條理. 當(dāng)然當(dāng)時(shí)的我還是菜鳥,寫js的程度還在只會(huì)使用jquery的階段,對(duì)于擴(kuò)展jquery是一無(wú)所知,更不用說(shuō)js閉包,用js模擬其他語(yǔ)言的OOP使用,以及設(shè)計(jì)模式這些比較專業(yè)的技巧了(其實(shí)現(xiàn)在對(duì)這些技術(shù)還在學(xué)習(xí)當(dāng)中). 我不可能憑空想出一個(gè)好的辦法來(lái),所以就開始參考其他性能比較出色的web2.0站的js代碼. 國(guó)外網(wǎng)站(如digg,netvibes)的js都用packer之類的東西加了密,人讀起來(lái)很困難,于是又轉(zhuǎn)向國(guó)內(nèi),看了看校內(nèi)等,js文件好多,畢竟是大型網(wǎng)站不適合.后來(lái)找到豆瓣,發(fā)現(xiàn)性能性能相當(dāng)出色,而且當(dāng)時(shí)的js也沒(méi)加密,只有三個(gè)文件jquery.js,suggest.js以及douban.js.其中最后一個(gè)文件是值得參考的.
當(dāng)時(shí)讀豆瓣的代碼也費(fèi)了不少勁. 我發(fā)現(xiàn)在豆瓣的html中有些元素的類(class)名稱很特別,比如(注意class屬性的值)
<input type="text" name="search_text" class="j a_search_text greyinput" autocomplete="off"/>
而且這些元素一般都是有js來(lái)增強(qiáng)交互效果的,比如表單元素,推薦按鈕等;在douban.js中也存在很多與上述一些元素類名稱命名一致的變量,比如
Douban.init_search_text = function(o){
//這里是相關(guān)代碼
}
于是我就想,豆瓣應(yīng)該是這樣想的:把js當(dāng)CSS來(lái)用,當(dāng)賦予某些元素特定的類名稱時(shí),該元素就會(huì)擁有相應(yīng)的js特性,比如上面說(shuō)的input元素?fù)碛蓄惷Qa_search_text,于是就擁有了Douban.init_search_text這個(gè)變量(或者說(shuō)函數(shù))賦予的js特性.這是怎么實(shí)現(xiàn)的呢?為了方便說(shuō)明,把douban.js簡(jiǎn)化如下,省略了細(xì)致末節(jié),大家可以大致看出主干:
//------第一段------
var Douban = new Object();
Douban.EventMonitor = function(){
this.listeners = new Object();
}
Douban.EventMonitor.prototype.broadcast=function(widgetObj, msg, data){/*代碼省略了*/};
Douban.EventMonitor.prototype.subscribe=function(msg, callback){/*代碼省略了*/};
Douban.EventMonitor.prototype.unsubscribe=function(msg, callback){/*代碼省略了*/};
//------第二段------
var event_monitor = new Douban.EventMonitor();
function load_event_monitor(root) {
var re = /a_(\w+)/;
var fns = {};
$(".j", root).each(function(i) {
var m = re.exec(this.className);
if (m) {
var f = fns[m[1]];
if (!f) {
f = eval("Douban.init_"+m[1]);
fns[m[1]] = f;
}
f && f(this);
}
});
}
$(function() {
load_event_monitor(document);
});
//------第三段------
Douban.init_evc = function(o) {/*...*/};
Douban.init_enb = function(o) {/*...*/};
Douban.init_folder_n = function(o){/*...*/};
Douban.init_unfolder = function(o){/*...*/};
...
可以把代碼分為三段:
讀懂豆瓣的代碼后,就開始部署自己的山寨版代碼,實(shí)施方法大致差不多(只不過(guò)把Douban對(duì)象換成了XM),就不再贅述,文章結(jié)尾有demo網(wǎng)址.這里介紹用這種方法的幾種技巧.
XM.init_confirm = function(o) {
if(!o.name){
$(o).click(function(){
var text = o.title || $(o).text();
return confirm("確定要"+text+"?");
});
}
使用示例
<a href="/delete" title="刪除這個(gè)帖子" class="j x_init_confirm">刪除</a>
點(diǎn)擊這個(gè)鏈接后會(huì)彈出確認(rèn)框,提示"確定要?jiǎng)h除這個(gè)帖子嗎?",點(diǎn)擊確定將前往刪除頁(yè)面,點(diǎn)"取消"可以取消操作
XM.URL = {
user_avatar: '/Content/i/ud.gif',
group_avatar:'/Content/i/gd.gif',
topic_thumb: '/Content/i/tnd.gif'
};
其他技巧會(huì)在本系列的后續(xù)文章中穿插提到. 大家有什么疑問(wèn)和建議,歡迎評(píng)論,希望共同提高!
Demo地址(也就是項(xiàng)目地址):鮮芒 (歡迎拍磚)
douban.js在這里: 下載
如對(duì)本文有疑問(wèn),請(qǐng)?zhí)峤坏浇涣髡搲瑥V大熱心網(wǎng)友會(huì)為你解答?。?點(diǎn)擊進(jìn)入論壇