近期要準(zhǔn)備一個(gè)web前端技術(shù)交流會(huì)的內(nèi)容,所以陸續(xù)會(huì)有一些整理的資料發(fā)布,JQuery目前在組內(nèi)日常開發(fā)中占據(jù)了重要地位,但各自為戰(zhàn)的情況 很明顯,要做到重用和通用,形成插件是不錯(cuò)的辦法,特別是基于JQuery的插件,具有使用簡(jiǎn)單,可參數(shù)化配置等優(yōu)點(diǎn)。這篇文章就介紹了如何開發(fā) JQuery的插件。原文地址是:http://www.learningjquery.com/2007/10/a-plugin-development-pattern
我已經(jīng)開發(fā)基于JQuery的插件有一段時(shí)間了,對(duì)于各種形式和要求的插件開發(fā)有了較好的掌握。在這里,我將在本文中分享我認(rèn)為十分有用的插件開發(fā) 方式。當(dāng)前前提是假定你對(duì)JQuery的插件開發(fā)有一定了解,如果你是插件開發(fā)的新手,不妨先看看jQuery官網(wǎng)上的the jQuery Authoring Guidelines。
我認(rèn)為以下插件開發(fā)模式是必須應(yīng)該掌握的:
1.在JQuery命名空間內(nèi)聲明一個(gè)特定的命名;2.接收參數(shù)來控制插件的行為;
3.提供公有方法訪問插件的配置項(xiàng)值;
4.提供公有方法來訪問插件中其他的方法(如果可能的話);
5.保證私有方法是私有的;
6.支持元數(shù)據(jù)插件;
下面,我將逐一講述上面的內(nèi)容,并在同時(shí)給出相關(guān)的簡(jiǎn)單插件開發(fā)代碼。
1.在JQuery命名空間內(nèi)聲明一個(gè)特定的命名這意味著開發(fā)的是一個(gè)單一命名的插件腳本,如果你的腳本包含多個(gè)插件或者有補(bǔ)充性質(zhì)的插件,比如$.fn.doSomething() 和$.fn.undoSomething(),那你得聲明多個(gè)命名了。但是總體來說,當(dāng)開發(fā)一個(gè)插件時(shí),我們應(yīng)該努力做到用一個(gè)單一的命名來搞定整個(gè)插 件。
在例子中,我們將聲明一個(gè)名為“hilight”的插件。
- $. fn . hilight = function () {
- ? // Our plugin implementation code goes here.
- } ;?
我們可以這樣調(diào)用:
$(’#myDiv’).hilight();
但是假如我們需要打破這種單一的命名和調(diào)用方式呢?有很多理由支持我們這么做:設(shè)計(jì)上的需要;更加簡(jiǎn)單和可讀的配置;而且那樣將更加符合OO的要求。
在沒有給命名空間來到麻煩的前提下,將插件的部署打破成為多個(gè)函數(shù)的形式將是十分繁瑣的。我們通過認(rèn)識(shí)并利用JavaScript中 functions是最高層的對(duì)象,和其他對(duì)象一樣,functions可以被賦予屬性,前面我們已經(jīng)將hilight命名聲明在了JQuery的原型對(duì) 象上,那么,其實(shí),其他的我們想擴(kuò)展的屬性或?qū)ο蠖寄軌蛟趆ilight上進(jìn)行聲明。稍后將詳細(xì)講述此點(diǎn)。
2.接收參數(shù)來控制插件的行為;來為我們的hilight插件添加指定前景和背景色的功能,我們需要在函數(shù)中允許一個(gè)object類型的選項(xiàng)設(shè)置。如下所展示的那樣:
- $. fn . hilight = function ( options ) {
- ? var ? defaults = {
- ?? ? foreground : ' red ' ,
- ?? ? background : ' yellow '
- ?? } ;
- ?? // Extend our default options with those provided.
- ?? var ? opts = $. extend ( defaults , options ) ;
- ?? // Our plugin implementation code goes here.
- } ;
現(xiàn)在,我們的插件可以這樣來調(diào)用:
$(’#myDiv’).hilight({
??foreground: ‘blue’
});
上面的代碼我們可以做一下改進(jìn),使得插件的默認(rèn)值可以在插件之外被設(shè)置。這無(wú)疑是十分重要的,因?yàn)樗沟貌寮脩艨梢允褂米钌俚拇a來修改插件配置,這其實(shí)是我們利用函數(shù)對(duì)象的開始。
- // plugin definition
- $. fn . hilight = function ( options ) ? {
- ?? // Extend our default options with those provided.
- ?? // Note that the first arg to extend is an empty object -
- ?? // this is to keep from overriding our "defaults" object.
- ?? var ? opts = $. extend ({} , $. fn . hilight . defaults , options ) ;
- ?? // Our plugin implementation code goes here.
- } ;
- ?
- // plugin defaults - added as a property on our plugin function
- $. fn . hilight . defaults = {
- ?? foreground : ' red ' ,
- ?? background : ' yellow '
- } ;
這里要講的方法和前面的講解一脈相承,用此方法來擴(kuò)展你的插件(而且能夠讓其他人進(jìn)行擴(kuò)展)是件很有意思的事情。例如,在擴(kuò)展hilight插件 時(shí),我們可以定義一個(gè)format方法用來格式化高亮顯示的文本,原來的hilight插件和擴(kuò)展了format方法的插件代碼如下:
- $. fn . hilight = function ( options ) {
- // iterate and reformat each matched element
- return ? this . each ( function () {
- var $ this = $ ( this ) ;
- ...
- var ? markup = $ this . html () ;
- // call our format function
- markup = $. fn . hilight . format ( markup ) ;
- $ this . html ( markup ) ;
- }) ;
- } ;
- ?
- // define our format function
- $. fn . hilight . format = function ( txt ) ? { '
- return ' < strong > ' + txt + ' < / strong>';
- };
如前面所述,我們已經(jīng)很容易的通過設(shè)置options對(duì)象的屬性來允許一個(gè)回調(diào)函數(shù)來覆寫默認(rèn)的格式設(shè)置。在這里有另外一個(gè)非常棒的方法來個(gè)性化你
的插件,上面展示的方法實(shí)際上就是通過暴露format方法,使其可以被重新定義。這種做法使得其他人可以采用他們自己的習(xí)慣和方式來重寫你的插件,這意
味著他們可以為你的插件寫額外的擴(kuò)展插件。
仔細(xì)考量一下前面我們用到的插件例子程序,你可能會(huì)想“我們究竟應(yīng)該在什么時(shí)候使用這種插件方式來實(shí)現(xiàn)需求”的問題。一個(gè)來自現(xiàn)實(shí)應(yīng)用中的插件便是“
Cycle
Plugin”,它是一個(gè)支持多種滑動(dòng)顯示特效的插件,特效包括滾動(dòng)、滑動(dòng)和漸變等等。但是,實(shí)際上,并沒有辦法來定義每一個(gè)可能會(huì)用在滑動(dòng)變幻上的特
效。這就是這種擴(kuò)展方式的有用之處。“ Cycle
Plugin”插件暴露了”transitions”對(duì)象,這使得用戶只需要按照如下方式便可以添加自己的變幻定義:
$.fn.cycle.transitions = {
…
};
這種技巧使得用戶可以定義或者采用自己習(xí)慣的方式來擴(kuò)展“ Cycle Plugin”。
上面提到的暴露插件中的公有方法的技巧使得插件能夠被覆寫,這將使插件變得十分靈活而強(qiáng)大,但至于哪一部分,那些屬性和方法應(yīng)該被暴露出來,你得小
心了。一旦使其能夠被外界訪問到,你就得注意到任何調(diào)用參數(shù)和語(yǔ)義化的變動(dòng)都可能使其喪失向前的兼容性。作為一般準(zhǔn)則,如果不確定是否應(yīng)該暴露某個(gè)屬性或
對(duì)象的話,那就最好別那樣做。
那么我們應(yīng)該怎樣來定義多個(gè)方法而不至于使命名空間混亂并且保證不被暴露再外呢?這就是閉包的工作,為了便于演示,我們給插件加入了一個(gè)叫做
“debug”的功能,它用來記錄firebug控制臺(tái)所選擇的網(wǎng)頁(yè)元素?cái)?shù)目。為了創(chuàng)建一個(gè)閉包,我們將整個(gè)功能的定義放入在一個(gè)function中了
(有關(guān)這方面的知識(shí),可參見JQuery手冊(cè))。
- // create closure
- ( function ( $ ) ? {
- // plugin definition
- $. fn . hilight = function ( options ) ? {
- debug ( this ) ;
- ...
- } ;
- // private function for debugging
- function ? debug ( $ obj ) {
- if ? ( window . console & amp ;& amp ; window . console . log )
- window . console . log ( ' hilight selection count: ' + $ obj . size ()) ;
- } ;
- ...
- // end of closure
- })( jQuery ) ;
debug方法在這里是無(wú)法被在插件以外訪問到的,因此,我們稱之為它是插件私有的。
6.支持元數(shù)據(jù)插件;根據(jù)你所寫的插件的類型,為你的插件加入元數(shù)據(jù)插件的支持將使其變得更強(qiáng)大。就我個(gè)人來說,喜歡采用元數(shù)據(jù)插件的重要原因便是它可以讓你使用定義之外的標(biāo)簽來覆寫你的插件屬性設(shè)置(這在創(chuàng)建demo和例子時(shí)十分有用),而且支持它十分的簡(jiǎn)單。
更新:這部分內(nèi)容可以在本文的評(píng)論中展開討論(既然有爭(zhēng)議的話)
- // plugin definition
- $. fn . hilight = function ( options ) ? {
- ...
- // build main options before element iteration
- var ? opts = $. extend ({} , $. fn . hilight . defaults , options ) ;
- return ? this . each ( function () {
- var $ this = $ ( this ) ;
- // build element specific options
- var ? o = $. meta ? $. extend ({} , opts , $ this . data ()) : opts ;
- ...
改動(dòng)部分的代碼會(huì)做如下的事情:
*測(cè)試metadata插件是否可用
*如果可以,將用metadata擴(kuò)展options對(duì)象
這被加入到j(luò)Query.extend,作為其最后一個(gè)參數(shù),所以它可以覆寫任何其他參數(shù)設(shè)置。現(xiàn)在我們可以通過下面的方式控制其行為:
- <!--? markup? -->
- < div ? class = " hilight { background: 'red', foreground: 'white' } " > Have a nice day! </ div >
- < div ? class = " hilight { foreground: 'orange' } " > Have a nice day! </ div >
- < div ? class = " hilight { background: 'green' } " > Have a nice day! </ div >
而在調(diào)用方面,我們通過一行簡(jiǎn)單的代碼就可以實(shí)現(xiàn)預(yù)期的效果:
$(’.hilight’).hilight();
將上面所述內(nèi)容涉及到的代碼放在一起,完整的例子程序代碼如下:
- //
- // create closure
- //
- ( function ( $ ) ? {
- //
- // plugin definition
- //
- $. fn . hilight = function ( options ) ? {
- debug ( this ) ;
- // build main options before element iteration
- var ? opts = $. extend ({} , $. fn . hilight . defaults , options ) ;
- // iterate and reformat each matched element
- return ? this . each ( function () {
- $ this = $ ( this ) ;
- // build element specific options
- var ? o = $. meta ? $. extend ({} , opts , $ this . data ()) : opts ;
- // update element styles
- $ this . css ({
- backgroundColor : o . background ,
- color : o . foreground
- }) ;
- var ? markup = $ this . html () ;
- // call our format function
- markup = $. fn . hilight . format ( markup ) ;
- $ this . html ( markup ) ;
- }) ;
- } ;
- //
- // private function for debugging
- //
- function ? debug ( $ obj ) {
- if ? ( window . console & amp ;& amp ; window . console . log )
- window . console . log ( ' hilight selection count: ' + $ obj . size ()) ;
- } ;
- //
- // define and expose our format function
- //
- $. fn . hilight . format = function ( txt ) ? {
- return ? ' <strong> ' + txt + ' </strong> ' ;
- } ;
- //
- // plugin defaults
- //
- $. fn . hilight . defaults = {
- foreground : ' red ' ,
- background : ' yellow '
- } ;
- //
- // end of closure
- //
- })( jQuery ) ;