|
在編寫本文中的插件時,我發現插件的創建過程以及用來創建它的框架非常簡單明了。困難的地方在于想一些其他人還沒有做過的事情,并編寫一些能真正完成某些操作的 JavaScript 代碼。由于插件結構簡單明了,對于新手它簡單易學,對于高手它很靈活,因此插件的數量急速上升。
當然,在研究本文所涉及的內容時,我還發現每個作者編寫插件的風格都不同,jQuery 允許好幾種不同的插件編寫風格。在本文中,我集中介紹最簡單的一種風格,以及 jQuery 本身推薦的一種風格,插件彈出后您就會看到差別或不同的選項。
描述插件
創建插件的第 1 步當然是想一個好點子。像大部分點子一樣,其他人總會給您創造機會。以我在本文中開發的插件為例,它不是什么新穎的概念,但在我撰寫文本的時候,jQuery 插件社區還找不到該插件。我知道我個人會從該插件中受益良多。
我的插件是一個 NumberFormatter 插件。處理服務器端代碼(比如 Java™ 或 php)和國際化的用戶應該很熟悉數字格式化。眾所周知,并非每個人都用相同的方式格式化數字。例如,并非每個人都使用 “里” 來度量距離。在美國,數字的寫法可能是 “1,250,500.75”(這個數字是從我的稅收表上抄來的),但在其他國家的寫法可能完全不同:德國是 “1.250.500,75”,法國是 “1 250 500,75”,瑞士是 “1'250'500.75”,日本是 “125,0500.75”。數字完全相同,但是在向 web 應用程序用戶展示時使用不同的格式。
因此,問題歸結到,當編寫一個國際化應用程序時,如何向不同國家的人展示這些數字?當然,解決方案是使用服務器端格式化,這種解決辦法非常常見。Java 有一個健壯的格式化庫,使數字的格式化變得非常簡單。當使用數字在服務器上設置頁面時,服務器負責處理這些數字。但是,很多時候數字可能不在服務器上,因此您需要一種方法在客戶機上格式化數字,而不需要與服務器會話。
我在這里描述的典型用例如下。您的 web 應用程序中有一個輸入字段,要求用戶輸入他們的薪水。在美國,用戶可能以各種格式輸入 “$65000”、“65,000”、“65000” 和 “65,000.00”。所有這些數字都是相同的,但是您需要控制這些數字在屏幕上的顯示方式,這樣才能提供更好的用戶體驗。您可以在輸入數字之后調用服務器,但是如果有許多使用不同格式的數字字段就太麻煩了。此外,如果您可以在客戶端處理該問題,并向用戶提供即時反饋,那么就不需要這樣做了。
因此,我建立了一個空缺,之后我將嘗試使用 JavaScript/jQuery 功能填補這一空缺。我的插件將在客戶機上提供數字格式化,為其他人提供一種國際化 web 應用程序的方式,且無需與服務器會話。作為額外的功能,我的插件還可以提供反向操作;該插件使開發人員能夠解析數字,從格式化的文本字符串中獲取數字。這還可以應用于客戶機上的數字操作。此外,我將模擬 JavaDecimalFormatter
類中的功能,以維護執行數字格式化的客戶端代碼和標準服務器端方法之間的通用性。
第 1 步結果:我發現了一個插件需求,然后定義了對于該需求我可以填補的空缺。
插件規則
jQuery 團隊建立了許多希望插件作者都能遵守的通用規則,為插件用戶創建一個通用而可信的環境。考慮到 jQuery 團隊比我聰明多了,我沒有理由違背這些規則,對不對?出于該原因,我在此列出這些規則,并且在插件的每一步都盡量遵守這些規則。
- 文件命名為 “
jquery.<your plug-in name>.js
”
這是有道理的,因為您希望用戶查看文件時立即知道這是一個 jQuery 插件以及這是哪個插件。檢查完畢。我的插件將命名為 “
jquery.numberformatter.js
”。 - 所有新方法都附加到 jQuery.fn 對象,所有新功能都附加到 jQuery 對象
現階段這可能有點難以理解,在下一節我將討論更多內容,因為這是實際編碼過程中最重要的規則。檢查完畢。我的方法/函數將僅附加到這兩個對象。
- “
this
” 用于引用 jQuery 對象
這有利于插件作者的編寫,它讓所有插件作者在引用 “this
” 時都知道將從 jQuery 收到哪個對象。檢查完畢。我將僅使用 “
this
” 引用 jQuery 對象。 - 插件中定義的所有方法/函數的末尾都必須帶有一個 “;”(分號),否則將不利于代碼的最小化。
因為這是最小化 JavaScript 文件的最佳實踐,大于最小值會很糟糕,您的插件有可能很快就被拋棄。檢查完畢。所有的方法/函數都將以 “;” 結尾。
- 除有特別注明外,所有方法都必須返回 jQuery 對象
jQuery 方法的順序鏈 (daisy-chaining) 非常著名,如果您編寫打破鏈條的插件,它就一定會 “打破鏈條”。檢查完畢。我的
format()
方法將返回 jQuery 對象,雖然我的parse()
方法沒有返回 jQuery 對象,但我在很多地方都注明該函數打破了鏈條。(畢竟,它不可能返回一個 Number 對象而不打破鏈條)。 - 您應該總是使用
this.each()
迭代匹配的元素,這是一種可靠而有效地迭代對象的方式。
出于性能和穩定性考慮,他們推薦所有的方法都使用它迭代匹配的元素。檢查完畢。我的方法都將只使用該方法迭代匹配的元素。
- 總是在插件代碼中使用 “jQuery” 而不是 “$”
這很重要,它使與 “$” 有沖突的用戶(那些使用另一個 JavaScript 庫的用戶)能夠使用 “var JQ = jQuery.noConflict();
” 函數更改他們的 jQuery 別名(pseudonym)。但是,在我查看許多插件時,我發現該規則常常得不到遵守,這太不幸了。如果開發人員需要更改 jQuery 別名,那么很可能意味著該插件要被棄用了。檢查完畢。在我的插件中,我將僅使用 jQuery 而不是它的別名 “$”。
好了,這些就是在插件代碼中必須遵守的規則和建議。真正的問題在于,它們實際上是強制性的,因為如果您不遵守這些插件規則,那么您的插件就得不到廣泛應用,而且還會得到不好的反饋。結果該插件很快就沒有人使用了,您所花費的時間都將白費。因此,遵守這些規則非常重要。這不僅能幫助您鶴立雞群,保證您代碼的統一性,還能增加插件的成功幾率。
第 2 步結果:我將遵守創建 jQuery 插件的所有規則
編寫插件
現在可以開始編寫代碼了!開始編寫插件的第一步是確定如何組織您的插件。開始有兩種選擇:您希望它是一個方法還是一個函數?“它們有區別嗎?”您可能會這樣問。
正如我上面提到的,方法需要附加到 jQuery.fn 對象,函數需要附加到 jQuery 對象。這樣一切都清楚了,不是嗎?如果您對 jQuery 相對不太了解,那么可能還不是很清楚。您可以這樣考慮。方法使代碼能夠迭代所有傳入插件的選定元素。因此,插件可以接收任何類型的 HTML 元素,由插件決定如何處理每個元素。因此,插件方法可以接收任何 jQuery 選擇器,所有從 “p” 到 “#mySpecificPageElement” 的內容。如果您希望插件更加靈活,允許用戶傳入任何類型的頁面元素,那么最好使用方法。插件開發人員應該負責正確地處理所有內容。相比之下,函數不使用任何選定元素作為參數。函數可以簡單地應用于整個頁面。這也由插件開發人員負責處理,開發人員必須定義他們希望與插件交互的頁面元素,并忽略其他元素。讓我們在代碼中看看不同之處。
清單 1. jQuery 插件方法/函數
// This is a method because you can pass any type of selector to the method and it // will take some action on the results of the selector. In this case, it will // doSomething() on the page element with an ID of myExample $("#myExample").doSomething(); // This is also a method, even though you are passing the entire page body to // the method, because you are still passing a selector $("body").doSomethingElse();
// This is a function, because you are NOT passing any selector to the function <div class="anotherThing"> // This hypothetical plug-in developer would document that his plug-in only works |
從這些描述中判斷,插件使用的似乎是方法,因為您需要讓用戶告訴您他們希望格式化哪些頁面元素。清單 2 展示了現在插件的代碼。
清單 2. 方法定義
jQuery.fn.format = function();
// You would call your plug-in like this (at this point) |
當然,您的函數不可能是放之四海而皆準的插件,因為您處理的是國際化情況,無法自動指出希望格式化文本的國家或者需要的格式。因此,您必須稍微修改插件以接收某些選項。格式化方法中需要兩個選項:數字應該使用的格式(例如,#,### 以及 #,###.00)和本地語言環境(本地語言環境是一個簡單的 2 字符國家代碼,用于確定要使用的國際數字格式)。
您還需要讓插件盡可能的易于使用,因為您必須提高插件的成功幾率。這意味著您應該繼續定義一些默認的選項,使用戶在不想傳入選項時不需要這樣做。我編寫插件的所在地是美國,這里使用的是世界上最常見的數字格式,我的默認語言環境是 “us”,格式默認為 “#,###.00”,因此貨幣自然要使用該默認值。
清單 3. 允許在插件中使用選項
jQuery.fn.format = function(options) {
// the jQuery.extend function takes an unlimited number of arguments, and each format: "#,###.00", }, options); |
創建插件框架的最后一步是正確處理傳入方法的選定元素。回想一下上例您會發現,選定元素可以是單頁面元素,或者是多頁面元素。您必須等效地處理它們。同樣,回想一下 jQuery 插件規則,"this"
對象只能引用 jQuery 對象。因此,您有一個對傳入方法的 jQuery 選定元素的引用,現在需要迭代它們。同樣,回顧規則讓我們知道,每個插件方法都應該返回 jQuery 對象。當然,您知道 jQuery 對象就是 "this"
,因此在方法中返回 this 完全沒有問題。讓我們看看如何在代碼片段中實現迭代每個選定元素并返回 jQuery 對象。
清單 4. 處理 jQuery 對象
jQuery.fn.format = function(options) {
var options = jQuery.extend( { format: "#,###.00", }, options); // this code snippet will loop through the selected elements and return the jQuery object |
由于實際插件本身不是本文的重點,我不對此進行詳細闡述,但是您可以在本文的插件代碼附件中看到全部內容(請參見 下載)。如果您決定編寫函數而不是方法,我還將向您展示一個樣例,介紹如何設置插件架構。
清單 5. 使用函數的示例插件
jQuery.exampleFunction = function(options) {
var options = jQuery.extend( { // your defaults }, options); }); |
調優插件
網上關于初級插件的大部分文章都到此為止了,這時它們會讓您采用基本的插件格式并運行。但是,這種基本架構也太 “基本” 了。在編寫插件時還必須考慮另一件重要的事情,給您插件增色所需要的內容遠不止一個初級插件那么簡單。再多增加兩個步驟,您就能將初級插件轉換為中級插件。
調優 #1 - 讓內部方法私有化
在任何面向對象的編程語言中,您會發現創建運行重復代碼的外部函數非常方便。在我創建的 NumberFormatter 插件中,有一個這種代碼的樣例 ―― 該代碼決定向函數傳遞哪個地理位置,以及要使用哪些字符作為小數點和分組符。format()
方法和 parse()
方法中都需要該代碼,任何一個初級程序員都會告訴您這屬于它自己的方法。但是,這會出現一個問題,因為您處理的是 jQuery 插件:如果您使用 JavaScript 中的定義將它作為自己的函數,那么任何人都可以為任何目的使用腳本調用該方法。這不是該函數的目的,我更傾向于不調用它,因為它僅用于內部工作。那么,讓我們看看如何將該函數私有化。
這種私有方法問題的解決方案稱為 Closure,它可以有效地從外部調用關閉整個插件代碼,附加到 jQuery 對象的除外(那些是公共方法)。通過這種設計,您可以將任何代碼放入插件中,不用擔心被外部腳本調用。通過將插件方法附加到 jQuery 對象,您可以有效地將它們變為公共方法,而讓其他的函數/類私有化。清單 6 展示了實現該操作所需的代碼。
清單 6. 私有化函數
// this code creates the Closure structure
(function(jQuery) {
// this function is "private"
function formatCodes(locale) {
// plug-in specific code here
}; // don't forget the semi-colon
// this method is "public" because it's attached to the jQuery object
jQuery.fn.format = function(options) {
var options = jQuery.extend( {
format: "#,###.00",
locale: "us"
},options);
return this.each(function(){
var text = new String(jQuery(this).text());
if (jQuery(this).is(":input"))
text = new String(jQuery(this).val());
// you can call the private function like any other function
var formatData = formatCodes(options.locale.toLowerCase());
// plug-in-specific code here
});
}; // don't forget the semi-colon to close the method
// this code ends the Closure structure
})(jQuery);
調優 #2 - 讓插件的默認值可覆蓋
調優插件的最后一步是讓它可以覆蓋默認值。畢竟,如果德國的開發人員下載了該插件,而且了解他的所有 web 應用程序用戶希望使用德文版本,那么您應該讓他能夠使用一行代碼修改默認語言環境,而不是要他在每個方法調用中都修改一遍。這樣您的插件才會非常方便,因為一個 web 應用程序不太可能使用不同的國際化格式向用戶展示數字。您在網頁上看一下就知道,所有數字都是使用同一個語言環境的格式。
該步驟要求您修改某處代碼,因此您將看到讓插件最為耀眼的一步。
清單 7. 覆蓋默認值
jQuery.fn.format = function(options) { return this.each(function(){ // define the defaults here as an object in the plug-in |
這是創建插件的最后一個步驟!這樣您就有了一個不錯的插件,可以進行最后的測試了。清單 8 展示了您可以放入本文的完整插件,以便您查看這些部分是如何變為一個整體的。此外還包含了 parse()
函數,到目前為止我還沒有討論過該函數,但是它包含在插件中(我沒有詳細介紹插件處理格式化的部分,因為它們不在本文討論之列。樣例中包含了該部分,插件本身當然也有)。
清單 8. NumberFormatter 插件
(function(jQuery) {
function FormatData(valid, dec, group, neg) { function formatCodes(locale) { jQuery.fn.parse = function(options) { var options = jQuery.extend({},jQuery.fn.parse.defaults, options); var formatData = formatCodes(options.locale.toLowerCase()); var valid = formatData.valid; var array = []; var text = new String(jQuery(this).text());
return array; jQuery.fn.format = function(options) { var options = jQuery.extend({},jQuery.fn.format.defaults, options); var formatData = formatCodes(options.locale.toLowerCase()); var valid = formatData.valid; return this.each(function(){ // formatting logic goes here if (jQuery(this).is(":input")) jQuery.fn.format.defaults = { |
測試插件
創建插件的最后一步是全面測試它。用戶在插件中發現 bug 會讓他們很惱火。用戶不會去修復它,他們會快速放棄使用它。如果有幾個這類用戶再加上一些糟糕的評論,您的插件很快就會石沉大海。此外,這是一個很好的互惠行為 ―― 您希望自己使用的插件都經過了很好的測試,那么您也應該提供經過良好測試的插件。
我創建了一個快速測試結構來測試我的插件(不需要單元測試庫),該結構創建了許多跨區,跨區中是一些數字,緊接數字后面的是該數字的正確格式。JavaScript 測試對數字調用格式,然后比較格式化的數字與想要的結果,如果失敗則顯示為紅色。通過該測試,我可以設置不同的測試用例,測試所有可能的格式(我已經這樣做了)。我將測試頁面附加到樣例 下載 中,以便您為測試自己插件找到一個可能的解決方案,利用 jQuery 進行測試。
查看完成的插件
讓我們看看運行中的新 NumberFormatter。我已經創建了一個簡單的 web 應用程序,您可以查看 NumberFormatter 插件如何滿足您的應用程序。
圖 1. 運行中的 NumberFormatter

這個 Web 應用程序很簡單,也很直接。當用戶離開文本字段時(輸入了薪水、住宅、子女信息之后),NumberFormatter 插件將相應地格式化其輸入的信息。該插件使 Web 應用程序能夠向用戶展示統一格式的數字。還要注意,該 web 應用程序是為德國用戶格式化的,因此小數點和分組符號與美國用戶不一樣(關于這一點,請讓我展示如何更改默認值)。
清單 9. 運行中的 NumberFormatter
$(document).ready(function() {
// use the AlphaNumeric plug-in to limit the input // you want to change the defaults to use the German locale // when the salary field loses focus, format it properly // when the house field loses focus, format it properly }); |
在結束之前,關于 NumberFormatter 插件還有幾件事情需要指出。首先,該插件是第一個 1.0.0 發行版,因此我希望將來進行擴展,包含更多 Java DecimalFormatter 中的格式化功能。包括支持貨幣、科學計數法和百分比。它還對負數和正數包含不同的格式化規則,負數不是簡單的 “-”(例如,對負數使用 (5,000),在會計中是這樣做的)。最后,一個好的格式器應該支持格式中的任何字符,而僅它忽略不屬于保留字符的部分。這都是我近期想添加的功能,希望該插件變得更加健壯。
獲取用戶的語言環境
最后一個問題與 jQuery 無關,但是使用該插件時可能會出現 ―― 如何獲取用戶的語言環境?這個問題提得很好,因為目前使用 JavaScript 沒有辦法獲取該信息。您需要創建一個 JavaScript Bridge 來實現該目的。什么是 JavaScript Bridge?我的意思是您可以建立一個簡單的設計模式將值從服務器端代碼傳入 JavaScript 代碼。清單 10 展示了您可以使用 Java 在 JSP 頁面做到這一點。
清單 10. 獲取用戶的語言環境
<%
// the request object is built into JSPs %> $(document).ready(function() { // take advantage of the ability to override defaults by using the JavaScript |
共享插件
最后,編寫和測試插件都做完了。最后一步是與他人共享該插件,并將它上傳到 jQuery 網站的插件存儲庫。
- 轉到 jQuery 網站的插件頁面,在左導航欄,單擊 Login/Register 然后單擊 Create New Account。如果已經有一個帳戶,請登錄;如果沒有,則創建一個新帳戶。
- 驗證通過后,左導航將出現一些選項。其中有一個 “Add plug-in”。
- 導航插件創建頁面。因為您只能使用 jQuery 1.2 測試該插件,您應該將其作為一個兼容版本包含在內。花一些時間為插件寫一個好標題以及一個好的描述。畢竟,現在是向其他用戶推銷該插件的時候了,您需要讓自己與眾不同。盡量講出該插件的好處。
- 該插件需要您提供插件主頁。雖然您創建了插件,但很可能沒有插件主頁。幸運的是,如果您沒有自己的服務器保存插件,Google 很樂于為開源項目提供空間。我選擇在 Google Code 中放置該插件。要建立自己的 Google Code 項目,只需要訪問 code.google.com 然后按照注冊流程注冊即可。
- 按下 Submit 之后您的插件就創建好了!
恭喜,您的插件現在是 jQuery 插件社區的一部分了,您現在正式成為開源項目的貢獻者之一。給自己一個 5 星評級以獎勵自己吧!因為您值得!
結束語
在本文中,我主要介紹如何為 jQuery JavaScript 框架創建插件。我從頭開始,構思了一個想法并將其付諸實現,介紹了創建該插件要使用的幾個步驟。然后,我閱讀了 jQuery “戒律”,它是為確保插件的一致性而設置的插件規則。我還在文章中提醒這些規則,因為我看到許多規則在插件中都沒有得到遵守,尤其是只能在插件中使用 “jQuery” 而不是 “$”(當然,我遵守了該規則)。
介紹了插件的背景,以及編寫插件的規則之后,您了解了基本的插件框架以及在插件中編寫方法與編寫函數的不同。方法應該在采用選定元素作為參數并對其執行某些操作時使用。提供頁面元素的任務由調用方法的人負責。另一方面,函數應該在對選定元素不感興趣時使用,因為您已經知道要執行操作的頁面元素。提供頁面元素的任務由編寫該函數的開發人員負責。這兩種形式的插件都是有效的,僅在在插件需求上有所不同。最后,查看設置默認選項的基本方式以及如何讓用戶提供自己的選項。
本文的下一步是為插件提供一些亮點,以增加它的先進性。該步驟給整個插件畫上了句號,有效地創建了私有函數和公共函數。我創建了一些在插件內部調用的函數,以便插件外部的人無法調用它們。您還可以看到如何向插件用戶展示默認值,讓用戶定義他們自己的默認值,輕松實現編碼。
最后,在樣例 web 應用程序中使用插件展示它的行為。本文的最后一部分是這些努力工作的最終成果 ―― 您需要將插件上傳到 jQuery 插件社區站點,讓它成為 JavaScript 庫的一部分。
JavaScript技術:jQuery創建自己的插件(自定義插件)的方法,轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。