jquery下組織javascript代碼(js函數(shù)化)
更新時間:2010年08月25日 19:10:46 作者:
這里整理的是jquery下js的一些代碼組織方法,大家可以借鑒下整理出基于jquery的自己喜歡的模式。
從神奇的"$"函數(shù)開始
"$"函數(shù)將在文檔加載完成之后為一個指定的button 綁定事件,這些代碼在單個網(wǎng)頁中工作正常。但是如果我們還有其它的網(wǎng)頁,我們將不得不重復(fù)這個過程。
<a href="javascript:;" id="sayHello">Say Hello</a>
<script type="text/javascript">
//when dom ready, do something.
//bind click event to a button.
$(function(){
$('#sayHello').click(function(){
alert('Hello world!');
});
});
</script>
如果我們需要另一個行為的button怎么辦?比如象這樣:
<a href="javascript:;" id="sayUnlike">Unlike it</a>
<script type="text/javascript">
//when dom ready, do something.
//bind click event to a button.
$(function(){
$('#sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
接下來,更多的問題出現(xiàn)了,我們需要很多這樣的button, 這好象也不難。
<a href="javascript:;" class="sayUnlike">Unlike it</a>
<script type="text/javascript">
//Change to a class selector to match all the button elements.
$(function(){
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
一個頁面里面同種出現(xiàn)了兩種button ......
<a href="javascript:;" class='sayHello'>Say Hello</a>
<a href="javascript:;" class="sayUnlike">Unlike it</a>
<script type="text/javascript">
$(function(){
$('.sayHello').click(function(){
alert('Hello world!');
});
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
但是呢,不是所有的頁面都會用到這兩種的button,為了不在頁面上使用額外的選擇器,我們要作一些必要的調(diào)整,因為基于class的選擇器的性能相對于id選擇器開銷很大,需要遍歷所有dom元素,并使用正則表達式匹配class屬性來選定滿足條件的元素。
<? if($page == 'A'){?>
<script type="text/javascript">
$(function(){
$('.sayHello').click(function(){
alert('Hello world!');
});
});
</script>
<? } ?>
<? if($page == 'B'){?>
<script type="text/javascript">
$(function(){
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
<? } ?>
我們的項目功能越來越復(fù)雜,經(jīng)過一段時間以后,變成了這個樣子, quick but dirty......
<? if($page == 'A' or $page == "C" and $page is not "D"){ ?>
<script type="text/javascript">
......
</script>
<? } ?>
<? if($page == "B" or $page == "E" and $page is not "X"){ ?>
<script type="text/javascript">
.....
</script>
<? } ?>
<? if($page == "B" or $page == "E" or $page == "C"){ ?>
<script type="text/javascript">
.....
</script>
<? } ?>
這真是太糟糕了,我們需要在一個頁面上加載許多個代碼片斷才能綁定所有的事件,如果我們再將不同的代碼分裝入多個js文件中這將增加多個頁面資源的http請求,不論是管理還是用戶體驗都將面臨挑戰(zhàn),我們需要找到一個更佳的解決方案。
既然 class selector 的開銷這么大,我們能不能在一次掃描中綁定所有的事件?我們可以嘗試一下:
<script type="text/javascript">
//Register global name space.
var Yottaa = Yottaa || {};
Yottaa.EventMonitor = function(){
this.listeners = {};
}
//Bind all event.
Yottaa.EventMonitor.prototype.subscribe=function(msg, callback){
var lst = this.listeners[msg];
if (lst) {
lst.push(callback);
} else {
this.listeners[msg] = [callback];
}
}
// Create the event monitor instance.
var event_monitor = new Yottaa.EventMonitor();
function load_event_monitor(root){
var re = /a_(\w+)/; //using a regular expression to filter all event object.
var fns = {};
$(".j", root).each(function(i) {
var m = re.exec(this.className);
if (m) {
var f = fns[m[1]];
if (!f) { //如果事件處理函數(shù)不存在則創(chuàng)建函數(shù)對象.
f = eval("Yottaa.init_"+m[1]);
fns[m[1]] = f;//調(diào)用綁定函數(shù).
}
f && f(this);
}
});
}
$(function(){
// when dom ready, bind all event.
load_event_monitor(document);
});
//Here is 2 sample components.
Yottaa.init_sayhello = function(obj){
$(obj).click(function(){
alert('Hello world!');
});
}
Yottaa.init_unlike = function(obj){
$(obj).click(function(){
alert('I unlike it.');
});
}
</script>
我們的DOM元素這樣寫:
<a href="javascript:;" class="j a_sayhello">Say Hello</a>
<a href="javascript:;" class="j a_unlike">Say Unlike</a>
這樣看起似乎好多了,我們只需要在頁面加載的時候執(zhí)行一次class selector(在上面的代碼中就是所有'.j'的元素)就可以找到所有需要綁定事件的元素,具體綁定哪一個組件由 class 名稱里面的 a_xxx 來決定,對應(yīng)著 Yottaa.init_xxx,并將當(dāng)前元素的引用作為參數(shù)傳入事件邏輯中。
在這個處理模式下,我們不需要再次手動編寫事件處理的邏輯并將它放到 $(function(){ .... }); 這樣的初始化函數(shù)中,所有我們要做的事情僅僅是給組件的“容器”加上兩個 class: "j a_XXX"程序即可幫我完成事件綁定工作,是不是很 cool ?象常用的展開/折疊效果,全選/反選效果, tab切換以致于一些其它的簡單功能都可以使用這種方式。難道這就是傳說中的銀彈?不,事情沒那么簡單,我們應(yīng)該看到這種處理方式一些弱點:
不能給組件傳遞初始化參數(shù)。
不能體現(xiàn)出組件的包含關(guān)系,也不能利用繼承和多態(tài)等面向?qū)ο蟮奶匦允钩绦蚋菀拙帉懞屠斫狻?
對于部分具體關(guān)聯(lián)關(guān)系的組件在處理上略顯麻煩,沒有合理的事件通知機制。
我們來看看第一條:關(guān)于參數(shù)的傳遞,在許多場景下對于多個條目的列表,對應(yīng)每一個條目我們一般會給元素分配一個唯一一的id,這些元素的行為類似,不同之處只是服務(wù)器端的編號不同,比如一個留言列表或者是一個產(chǎn)口列表。我們可以利用id屬性為我們作一些事情,看下面的代碼,我們用id屬性把條目對應(yīng)的服務(wù)器端編號告訴javascript,并在接下來的事件邏輯處理中作為服務(wù)器回調(diào)函數(shù)參數(shù)的一部分發(fā)回服務(wù)器端。
<script type="text/javascript">
Yottaa.init_sampleajax = function(obj){
$(obj).click(function(){
var component_id = $(this).attr('id').split('-')[1];
$.get('/server/controller/method', {id: component_id}, function(data){
if(data){
alert('Message from server: ' + data );
}
});
});
}
</script>
<a href="javascript:;" class='j a_sampleajax' id='item-a'>Show server message. </a>
<a href="javascript:;" class='j a_sampleajax' id="item-b">Another button with same action but different server side identifier.</a>
在更復(fù)雜的一些場景中我們可以利用頁面上的inline code給組件傳遞一些必要的信息。
Yottaa.globalConst = {
User:{
familyName: "Jhone",
givenName: 'bruce'
},
Url:{
siteName: 'yottaa.com',
score: 98
}
}
Yottaa.componentMetaData = {
compoment_id_1:{ ...... },
component_id_2:{ ...... }
};
上面討論了一種可能的代碼組織辦法,但是并非適用于所有的項目,我們要做的是:針對于目前的現(xiàn)狀,找到一個在代價比較小的重構(gòu)方案。我們考慮如下幾點:
分離元素的事件綁定代碼和組件代碼:組件代碼包括jquery庫,相關(guān)擴展插件,以及我們自己編寫的小部件,如chartbox等內(nèi)容。
事件綁定及處理邏輯:按不同的組件劃分為多個模塊,每個模塊放入一個function中。
頁面需要指定哪些模塊要在本頁面上初始化,提供一個列表交由全局的事件綁定器統(tǒng)一處理。
下面來演示一下部分代碼:
<script type="text/javascript">
function init_loginPanel = function(){
var container = $('login_panel');
$('#login_button').click(function(){
......
});
}
function init_chart = function(){
......
}
//global static init method
Yottaa.initComponents = function(components){
for(var i = 0;i<components.length;i++){
if(typeof window[components[i]] == 'Function'){
window[components[i]]();
}
}
}
// above is in the 'all-in-one' assets file which is compressed to one file in production.
var components = ['init_loginPanel', 'init_chart'];
var metaData = {
loginPanel: {},
chart: {},
......
};
$(function(){
Yottaa.initComponents(components);
});
//here is inline script on the page.
</script>
"$"函數(shù)將在文檔加載完成之后為一個指定的button 綁定事件,這些代碼在單個網(wǎng)頁中工作正常。但是如果我們還有其它的網(wǎng)頁,我們將不得不重復(fù)這個過程。
復(fù)制代碼 代碼如下:
<a href="javascript:;" id="sayHello">Say Hello</a>
<script type="text/javascript">
//when dom ready, do something.
//bind click event to a button.
$(function(){
$('#sayHello').click(function(){
alert('Hello world!');
});
});
</script>
如果我們需要另一個行為的button怎么辦?比如象這樣:
復(fù)制代碼 代碼如下:
<a href="javascript:;" id="sayUnlike">Unlike it</a>
<script type="text/javascript">
//when dom ready, do something.
//bind click event to a button.
$(function(){
$('#sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
接下來,更多的問題出現(xiàn)了,我們需要很多這樣的button, 這好象也不難。
復(fù)制代碼 代碼如下:
<a href="javascript:;" class="sayUnlike">Unlike it</a>
<script type="text/javascript">
//Change to a class selector to match all the button elements.
$(function(){
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
一個頁面里面同種出現(xiàn)了兩種button ......
復(fù)制代碼 代碼如下:
<a href="javascript:;" class='sayHello'>Say Hello</a>
<a href="javascript:;" class="sayUnlike">Unlike it</a>
<script type="text/javascript">
$(function(){
$('.sayHello').click(function(){
alert('Hello world!');
});
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
但是呢,不是所有的頁面都會用到這兩種的button,為了不在頁面上使用額外的選擇器,我們要作一些必要的調(diào)整,因為基于class的選擇器的性能相對于id選擇器開銷很大,需要遍歷所有dom元素,并使用正則表達式匹配class屬性來選定滿足條件的元素。
復(fù)制代碼 代碼如下:
<? if($page == 'A'){?>
<script type="text/javascript">
$(function(){
$('.sayHello').click(function(){
alert('Hello world!');
});
});
</script>
<? } ?>
<? if($page == 'B'){?>
<script type="text/javascript">
$(function(){
$('.sayUnlike').click(function(){
alert('I unlike it.');
});
});
</script>
<? } ?>
我們的項目功能越來越復(fù)雜,經(jīng)過一段時間以后,變成了這個樣子, quick but dirty......
復(fù)制代碼 代碼如下:
<? if($page == 'A' or $page == "C" and $page is not "D"){ ?>
<script type="text/javascript">
......
</script>
<? } ?>
<? if($page == "B" or $page == "E" and $page is not "X"){ ?>
<script type="text/javascript">
.....
</script>
<? } ?>
<? if($page == "B" or $page == "E" or $page == "C"){ ?>
<script type="text/javascript">
.....
</script>
<? } ?>
這真是太糟糕了,我們需要在一個頁面上加載許多個代碼片斷才能綁定所有的事件,如果我們再將不同的代碼分裝入多個js文件中這將增加多個頁面資源的http請求,不論是管理還是用戶體驗都將面臨挑戰(zhàn),我們需要找到一個更佳的解決方案。
既然 class selector 的開銷這么大,我們能不能在一次掃描中綁定所有的事件?我們可以嘗試一下:
復(fù)制代碼 代碼如下:
<script type="text/javascript">
//Register global name space.
var Yottaa = Yottaa || {};
Yottaa.EventMonitor = function(){
this.listeners = {};
}
//Bind all event.
Yottaa.EventMonitor.prototype.subscribe=function(msg, callback){
var lst = this.listeners[msg];
if (lst) {
lst.push(callback);
} else {
this.listeners[msg] = [callback];
}
}
// Create the event monitor instance.
var event_monitor = new Yottaa.EventMonitor();
function load_event_monitor(root){
var re = /a_(\w+)/; //using a regular expression to filter all event object.
var fns = {};
$(".j", root).each(function(i) {
var m = re.exec(this.className);
if (m) {
var f = fns[m[1]];
if (!f) { //如果事件處理函數(shù)不存在則創(chuàng)建函數(shù)對象.
f = eval("Yottaa.init_"+m[1]);
fns[m[1]] = f;//調(diào)用綁定函數(shù).
}
f && f(this);
}
});
}
$(function(){
// when dom ready, bind all event.
load_event_monitor(document);
});
//Here is 2 sample components.
Yottaa.init_sayhello = function(obj){
$(obj).click(function(){
alert('Hello world!');
});
}
Yottaa.init_unlike = function(obj){
$(obj).click(function(){
alert('I unlike it.');
});
}
</script>
我們的DOM元素這樣寫:
<a href="javascript:;" class="j a_sayhello">Say Hello</a>
<a href="javascript:;" class="j a_unlike">Say Unlike</a>
這樣看起似乎好多了,我們只需要在頁面加載的時候執(zhí)行一次class selector(在上面的代碼中就是所有'.j'的元素)就可以找到所有需要綁定事件的元素,具體綁定哪一個組件由 class 名稱里面的 a_xxx 來決定,對應(yīng)著 Yottaa.init_xxx,并將當(dāng)前元素的引用作為參數(shù)傳入事件邏輯中。
在這個處理模式下,我們不需要再次手動編寫事件處理的邏輯并將它放到 $(function(){ .... }); 這樣的初始化函數(shù)中,所有我們要做的事情僅僅是給組件的“容器”加上兩個 class: "j a_XXX"程序即可幫我完成事件綁定工作,是不是很 cool ?象常用的展開/折疊效果,全選/反選效果, tab切換以致于一些其它的簡單功能都可以使用這種方式。難道這就是傳說中的銀彈?不,事情沒那么簡單,我們應(yīng)該看到這種處理方式一些弱點:
不能給組件傳遞初始化參數(shù)。
不能體現(xiàn)出組件的包含關(guān)系,也不能利用繼承和多態(tài)等面向?qū)ο蟮奶匦允钩绦蚋菀拙帉懞屠斫狻?
對于部分具體關(guān)聯(lián)關(guān)系的組件在處理上略顯麻煩,沒有合理的事件通知機制。
我們來看看第一條:關(guān)于參數(shù)的傳遞,在許多場景下對于多個條目的列表,對應(yīng)每一個條目我們一般會給元素分配一個唯一一的id,這些元素的行為類似,不同之處只是服務(wù)器端的編號不同,比如一個留言列表或者是一個產(chǎn)口列表。我們可以利用id屬性為我們作一些事情,看下面的代碼,我們用id屬性把條目對應(yīng)的服務(wù)器端編號告訴javascript,并在接下來的事件邏輯處理中作為服務(wù)器回調(diào)函數(shù)參數(shù)的一部分發(fā)回服務(wù)器端。
復(fù)制代碼 代碼如下:
<script type="text/javascript">
Yottaa.init_sampleajax = function(obj){
$(obj).click(function(){
var component_id = $(this).attr('id').split('-')[1];
$.get('/server/controller/method', {id: component_id}, function(data){
if(data){
alert('Message from server: ' + data );
}
});
});
}
</script>
<a href="javascript:;" class='j a_sampleajax' id='item-a'>Show server message. </a>
<a href="javascript:;" class='j a_sampleajax' id="item-b">Another button with same action but different server side identifier.</a>
在更復(fù)雜的一些場景中我們可以利用頁面上的inline code給組件傳遞一些必要的信息。
復(fù)制代碼 代碼如下:
Yottaa.globalConst = {
User:{
familyName: "Jhone",
givenName: 'bruce'
},
Url:{
siteName: 'yottaa.com',
score: 98
}
}
Yottaa.componentMetaData = {
compoment_id_1:{ ...... },
component_id_2:{ ...... }
};
上面討論了一種可能的代碼組織辦法,但是并非適用于所有的項目,我們要做的是:針對于目前的現(xiàn)狀,找到一個在代價比較小的重構(gòu)方案。我們考慮如下幾點:
分離元素的事件綁定代碼和組件代碼:組件代碼包括jquery庫,相關(guān)擴展插件,以及我們自己編寫的小部件,如chartbox等內(nèi)容。
事件綁定及處理邏輯:按不同的組件劃分為多個模塊,每個模塊放入一個function中。
頁面需要指定哪些模塊要在本頁面上初始化,提供一個列表交由全局的事件綁定器統(tǒng)一處理。
下面來演示一下部分代碼:
復(fù)制代碼 代碼如下:
<script type="text/javascript">
function init_loginPanel = function(){
var container = $('login_panel');
$('#login_button').click(function(){
......
});
}
function init_chart = function(){
......
}
//global static init method
Yottaa.initComponents = function(components){
for(var i = 0;i<components.length;i++){
if(typeof window[components[i]] == 'Function'){
window[components[i]]();
}
}
}
// above is in the 'all-in-one' assets file which is compressed to one file in production.
var components = ['init_loginPanel', 'init_chart'];
var metaData = {
loginPanel: {},
chart: {},
......
};
$(function(){
Yottaa.initComponents(components);
});
//here is inline script on the page.
</script>
相關(guān)文章
JavaScript學(xué)習(xí)歷程和心得小結(jié)
在過去,JavaScript只是被用來做一些簡單的網(wǎng)頁效果,比如表單驗證、浮動廣告等,所以那時候JavaScript并沒有受到重視。2010-08-08
De facto standard 世界上不可思議的事實標(biāo)準(zhǔn)
前些天IEBlog中提到實現(xiàn)互通并不是只靠標(biāo)準(zhǔn)就行,其中舉出了一些關(guān)于事實上的標(biāo)準(zhǔn)的考慮——所謂“事實上的標(biāo)準(zhǔn)”,也就是并非標(biāo)準(zhǔn),但大家都遵循著它去做事情的那么一種東西。2010-08-08
JavaScript中的prototype.bind()方法介紹
在JavaScript中,我們經(jīng)常用到函數(shù)綁定,而當(dāng)你需要在另一個函數(shù)中保持this上下文時,使用Function.prototype.bind()會很方便2014-04-04
詳解JavaScript設(shè)計模式開發(fā)中的橋接模式使用
橋接模式的適用場合非常廣泛,除了在事件回調(diào)函數(shù)與接口之間進行橋接外,橋接模式也可以用于連接公開的API代碼和私用的實現(xiàn)代碼,下面我們就來詳解JavaScript設(shè)計模式開發(fā)中的橋接模式使用2016-05-05
JavaScript關(guān)鍵字this的用法總結(jié)
這篇文章介紹了JavaScript關(guān)鍵字this的用法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06
Javascript基礎(chǔ)教程之JavaScript語法
本文是javascript基礎(chǔ)教程的第一篇,給大家?guī)淼氖莏avascript的最基礎(chǔ)的東西--javascript的語法的注意事項,希望大家能夠喜歡2015-01-01

