不只是口號 jQuery的設(shè)計藝術(shù)
jQuery是一個了不起的輕量級的JavaScript框架,事實上在jQuery發(fā)布之前,就已經(jīng)有無數(shù)功能強大得多的JavaScript框架在流行。從功能列表上來說,jQuery在JavaScript框架中只能算是很不起眼的小弟。
但這個小弟在短短的時間內(nèi),就成為了最流行的JavaScript框架之一。當然jQuery成功的原因有很多,跨瀏覽器兼容、輕巧、不算很差的性能,以及jQuery的“口號”:write less, do more。
51CTO推薦閱讀:jQuery四大天王:核心函數(shù)詳解
有人會說,write less, do more就是jQuery的全部設(shè)計哲學,但我不這么認為。在我看來,write less, do more是任何一個框架都必須去做的事情。很難想象會有人選擇一個write more, do less的框架吧。所以,對于一個框架而言,這是最基本的事情,要成為一個偉大的框架,顯然這很不夠。
在這里我想談談jQuery的一個設(shè)計的藝術(shù),select then do。CSS選擇器是jQuery最重要的函數(shù)$(或者說jQuery)最常見的參數(shù)。盡管這個函數(shù)可以接受的參數(shù)還有HTML元素或是HTML代碼。但最常用的顯然是傳入一個CSS選擇器,jQuery會幫你選擇文檔中符合要求的元素。然后,你就可以對這個元素集進行操作:
- $("li").css("font-style", "italic");
這段腳本可以將所有l(wèi)i元素設(shè)置為斜體。這是jQuery最常見的用法,利用選擇器選擇自己所需的元素,然后對其執(zhí)行某些操作。為了方便進行多個操作,jQuery絕大多數(shù)的函數(shù)都返回執(zhí)行函數(shù)的原對象,在這里也就是$("li")。所以我們可以簡單的繼續(xù)寫:
- $("li").css("font-style", "italic").hide();
這里面透露出來了一個jQuery設(shè)計的哲學,即select then do,select就是選擇所需的元素,do就是執(zhí)行某些操作。絕大多數(shù)時候,我們都是select.do.do.select.do.do.do,比如說:
- $("li").css("font-style", "italic").show().find("a").text("刪除").attr("href", "javascript:void(0);").click(function ()
- { $(this).parent().hide(); });
很明顯的,$("li")在select然后接著兩個do,再然后.find("a"),這里在進一步進行select,然后繼續(xù)執(zhí)行一系列的do。注意在click綁定的事件處理函數(shù)里:$(this).parent().hide()也是一個非常經(jīng)典的select.select.do。這非常接近我們的自然語言,比如說上面那一段腳本,其實是這個意思:
“所有的li元素聽好了,把你們的字體搞成斜的,再給我顯示出來,然后看看你們后代里面有沒有a元素,讓它把顯示文字變成“刪除”,再把href屬性設(shè)置為"javascript:void(0);",最后他們被點擊的時候,把他們的父親隱藏掉。”是的,我完全是照著腳本直接就可以說出來,不需要任何思考和變換。接下來,我們來看看一個糟糕的例子:
- var items = document.getElementsByTagName("li" );
- for (var i = 0; i < items.length; i++)
- { var li = items.item(i);
- li.style.fontStyle = "italic";
- li.style.display = "";
- var childs = li.childNodes;
- for (var j = 0; j < childs.length; j++)
- { var a = childs[j];
- if (a.tagName != "A")
- continue;
- a.innerText = "刪除";
- a.href = "javascript:void(0);";
- a.onclick = function ()
- { this.parentNode.style.display = "none";
- };
- }
- }
很難想象這段腳本只是完成了相同的事情。照著這段腳本你能簡單的描述它是干什么的么?
當然,select then do并不僅僅只是幫我們節(jié)省了代碼。更大的優(yōu)勢在于,它使得我們可以將我們的邏輯和HTML文檔徹底的分開。簡單的說,在Web開發(fā)中,我們經(jīng)常會遇到這樣的需求,按下一個按鈕,彈出一個選擇框讓用戶決定是否提交表單,傳統(tǒng)的方式是這樣:
- <input type="button" id="submitButton" value="提交" onclick="if
- ( confirm( '您確定要提交這些信息么' ) )
- document.getElementById('registerForm').submit();" />
顯然這很糟糕,他將行為和HTML元素死死的捆在了一起,如果我們希望這個按鈕同時干兩件事情,那真是一件災難。jQuery的選擇器可以很好的幫助我們分離我們的行為,select then do:
- $("#submitButton").click(function ()
- { if (confirm('您確定要提交這些信息么'))
- $('#registerForm').submit(); });
如果是要處理復雜的事情,這會更愜意。其實到現(xiàn)在并沒有什么神奇的事情發(fā)生,沒有jQuery我們也可以通過DOM提供的方法簡單的通過腳本進行事件的注冊,而不是直接寫在HTML里面。只是我們要處理一下不同的瀏覽器之間的差異而已。
#p#
我們來考慮另一個場景。譬如說在頁面上有一個登陸的小區(qū)域,里面有三個輸入框,用戶名、密碼和驗證碼,然后有一個登陸按鈕,像這樣:
- <form action="/login" id="loginForm">
- <table border="0" cellpadding="5" cellspacing="0">
- <tr>
- <td>用戶名:</td>
- <td><input type="text" name="username" style="width: 100px;" /></td>
- </tr>
- <tr>
- <td>密碼:</td>
- <td><input type="password" name="password" style="width: 100px;" /></td>
- </tr>
- <tr>
- <td>驗證碼:</td>
- <td><input type="text" name="validateCode" style="width: 50px;" /><img src="validateCode.img" /></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="登陸" /></td>
- </tr>
- </table>
- </form>
有一個很不幸的事情,這種登陸框到處都有。而你,還不得不給這個登陸框加上一些必須處理的事情,例如在提交的時候檢查一下輸入框是不是空的。顯然我們并不希望在所有的這些頁面都去寫一小段腳本,我們希望有一段腳本,能夠自動的在有這種登陸框的頁面處理這些事情。最好是,在沒有登陸框的頁面,它也不會有任何副作用,那么這樣的腳本真的存在么?
- $("form#loginForm input[type=submit]").click(function ()
- {
- var form = $("form#loginForm");
- var flag = true;
- form.find("input[type=text] , input[type=password]").each(function ()
- { if (this.value == "" && flag)
- { window.alert("請將登陸信息填寫完整");
- flag = false;
- }
- });
- return flag;
- }
- );
注意這段腳本中選擇器的運用,通過id限定和find方法的范圍限定,我們牢牢地將這段腳本所影響的范圍控制在了一個id為loginForm的表單中。更絕妙的是,即使這個表單不存在于頁面,這段腳本也沒有任何的問題。不會在你IE的狀態(tài)欄弄一個黃色的感嘆號告訴你腳本出現(xiàn)了錯誤。你可以將這段腳本大膽放心的放在每一個頁面的JavaScript的引用中(這對于現(xiàn)有的技術(shù)來說再簡單不過),也不用擔心明天哪個頁面多了一個登陸塊你會需要去寫什么腳本。
這就是選擇器的絕妙之處,它使得我們的頁面元素可以通過約定來獲得某些行為,例如在這里,只要我們將登陸用的表單的id設(shè)置為loginForm,那么這個表單就會自動獲得提交的時候檢查所有輸入框的行為。這種約定的威力完全不僅如此,我們再來看一段神奇的腳本:
- $("form").submit(function ()
- {
- var flag = true;
- $(this).find("input[type=text][requiredrequired=required] , input[type=password][requiredrequired=required]").each(function ()
- {
- if ($(this).val() == "")
- { window.alert("信息沒有填寫完整,請認真檢查必填項");
- flag = false; return false;
- }
- }
- );
- return flag;
- }
- );
這段神奇的腳本可以讓你只需要在你的輸入框上加一個屬性required="required",然后表單提交的時候就會自動驗證這些輸入框里面是不是填了東西。這太神奇了,我們利用jQuery提前享受了HTML 5的新特性。
當我意識到j(luò)Query的選擇器如此強大的威力的時候,我馬上想到,事實上如果將選擇器運用于我們傳統(tǒng)的頁面數(shù)據(jù)綁定,也會是一件非常棒的事情。這便是Jumony引擎的由來。Jumony將jQuery的選擇器和select then do藝術(shù)幾乎完整的搬到了C#中。在項目開發(fā)中帶來的效率提升和暢快的感覺,完全的超出了我原本的設(shè)想。
在這里,我仍不愿意過多的去談Jumony的功能細節(jié)。由于這個引擎仍在不斷的開發(fā)修改和內(nèi)部測試中,現(xiàn)在并沒有可以公開的預覽,我只能說,敬請期待。我會繼續(xù)分享在Jumony開發(fā)和設(shè)計中過程中的。
最新的Jumony build已經(jīng)實現(xiàn)如下選擇器支持:
- *、E、E E、E + E、E > E、E ~ E
- #identity、.class-name、[attr]、[attr=value]
- [attr!=value]、[attr^=value]、[attr$=value]
- :nth-child、:nth-last-child、:nth-of-type、
- :nth-last-of-type、:first-child、:last-child、
- :first-of-type、:last-of-type
【編輯推薦】