插件實(shí)現(xiàn)方式
1、聲明立即調(diào)用函數(shù)
定義一個(gè)立即調(diào)用的函數(shù)聲明,如代碼清單2-1所示。在參數(shù)里傳入jQuery對(duì)象,通過參數(shù)$引入變量
,這樣其所有代碼在使用jQuery的時(shí)候,直接使用$符即可。這樣的做法,有以下兩個(gè)好處:?函數(shù)內(nèi)部的$符變量代表了局部變量,而不是全局變量里代表jQuery的$符變量,以達(dá)到防止變量污染的目的。?內(nèi)部的代碼全部都是私有代碼,外部代碼無法訪問,只有通過第三步,在$.fn上設(shè)置了插件(比如$.fn.alert=)的形式,通過$符變量才能將整個(gè)插件通過唯一的接口$.fn.alert暴露出去,從而保護(hù)了其內(nèi)部代碼。
注意:在function關(guān)鍵字前面有一個(gè)加號(hào)運(yùn)算符(+),其主要目的是防止前面有未正常結(jié)束的代碼(通常是遺漏了分號(hào)),導(dǎo)致前后代碼被編譯器認(rèn)為是一體的,從而導(dǎo)致代碼運(yùn)行出錯(cuò)。
2、定義相關(guān)插件類及原型方法
例如:alert prototype.close
步驟2 定義該插件的核心代碼,也就是在觸發(fā)特定行為(通常是單擊行為)后要進(jìn)行處理的代碼。插件核心代碼示例// alert插件類及原型方法的定義// 定義選擇器,所有符合該自定義屬性的元素都可以觸發(fā)下面的事件
通過上述代碼可以看出,主要是先定義了插件插件的類函數(shù)Alert,然后再定義需要用到的一些原型函數(shù),比如close函數(shù)方法。Alert函數(shù)接收el參數(shù),el表示DOM元素,一個(gè)DOM如果綁定了data-dismiss="alert"自定義屬性,則在單擊的時(shí)候就會(huì)觸發(fā)close函數(shù)方法,從而達(dá)到關(guān)閉的目的。同樣,Modal插件也是先定義Modal類函數(shù),然后再在Modal的原型上定義toggle和show等方法,其內(nèi)部根據(jù)相應(yīng)的規(guī)則再細(xì)化處理。
3、在jquery上定義插件,并重設(shè)插件構(gòu)造函數(shù)
例如:$.fn.alert.Constructor=Alert
在jQuery上定義插件,以便通過jQuery.插件名稱的方式,也能夠使用該插件,也就是在觸發(fā)特定行為(通常是單擊行為)后要進(jìn)行處理的通用代碼。最后在這里再調(diào)用插件類或原型方法。主要源碼如代碼清單2-3所示。代碼清單2-3jQuery插件定義// 在jQuery上定義alert插件,并重設(shè)插件構(gòu)造器var old = $.fn.alert// 保留其他插件的$.fn.alert代碼(如果定義),以便在noConflict之后,可以繼續(xù)使用該舊代碼$.fn.alert = function (option) {
jQuery插件的定義使用了標(biāo)準(zhǔn)的方法,在fn上進(jìn)行擴(kuò)展。在附加擴(kuò)展之前,首先“備份”之前插件(或別的框架提供的同名插件)的舊代碼,以方便在后面防沖突的時(shí)候使用。在附加擴(kuò)展之后,重新設(shè)置插件的構(gòu)造器(即Constructor屬性)為內(nèi)部定義的插件類函數(shù)自身,這樣就可以通過Constructor屬性查詢到插件的真實(shí)類函數(shù),使用new操作符實(shí)例化$.fn.alert的時(shí)候也不會(huì)出錯(cuò)。
注意:即便不聲明第三步,HTML聲明式的方式也是可以用的。所以說,第三步是專門為某些喜歡用JavaScript代碼觸發(fā)事件的人所準(zhǔn)備的。但需要注意的是,如果不聲明第三步,那第四步的防沖突的功能也就沒法用了。
4、防止沖突處理
例如:$.fn.alert.noConflict
防沖突處理,目的是讓Bootstrap插件和其他UI庫的同名插件共存。Bootstrap所有的插件都支持防沖突(noConflict)功能。源碼如代碼清單2-4所示。
這樣一旦有了一個(gè)同名的插件,比如A庫里有個(gè)同名$.fn.alert插件,則Bootstrap在執(zhí)行之前就通過old先備份了,然后執(zhí)行$.fn.alert.noConflict()后就會(huì)還原該old對(duì)象插件;而使用Bootstrap的alert插件的話,則通過varalert=$.fn.alert.noConflict()的形式,將Bootstrap的alert插件轉(zhuǎn)移到另外一個(gè)變量上,從而進(jìn)行使用。
5、綁定各種觸發(fā)事件
在一切都就緒之后,綁定默認(rèn)的觸發(fā)事件。由于已經(jīng)為jQuery提供了默認(rèn)的$.fn.alert擴(kuò)展插件功能,已經(jīng)可以通過手工編寫JavaScript代碼來觸發(fā)事件了。這里的第五步主要是為聲明式的HTML觸發(fā)事件,即:在HTML文檔里已經(jīng)按照布局規(guī)則聲明了相關(guān)的自定義屬性(比如data-dismiss="alert"),然后通過這里的代碼初始化默認(rèn)的單擊事件行為(或其他相關(guān)插件需要用到的行為)。綁定觸發(fā)事件的源碼如下所示:
// 綁定觸發(fā)事件
// 為聲明式的HTML綁定單擊事件
// 在整個(gè)document對(duì)象上,檢測(cè)是否有自定義屬性data-dismiss="alert"
// 如果有,則設(shè)置:單擊的時(shí)候,關(guān)閉指定的警告框元素
上述代碼在整個(gè)document文檔上檢測(cè)自定義屬性datadismiss="alert",如果有,則綁定click單擊事件(在命名空間bs.alert.data-api上),事件回調(diào)函數(shù)則是原型方法Alert.prototype.close。這樣,一旦單擊了相應(yīng)的元素,就會(huì)關(guān)閉特定的警告框。
Bootstrap通過這5個(gè)通用步驟,定義了所有的插件。每個(gè)插件在各個(gè)步驟里會(huì)有一些細(xì)節(jié)的不同,但思路都是一樣的,那就是:綁定事件,觸發(fā)行為,并在jQuery上擴(kuò)展fn,同時(shí)解決防沖突的問題。大家在制作自定義插件的時(shí)候只要遵從這一思路,即可編寫出既易于維護(hù)又高質(zhì)量的插件代碼。
2.4.3 通用技術(shù)根據(jù)上述JavaScript插件的實(shí)現(xiàn)步驟,來總結(jié)一下JavaScript插件的通用技術(shù),即Bootstrap的開發(fā)者在開發(fā)這些插件時(shí)所制定的規(guī)則和遵循的標(biāo)準(zhǔn),同時(shí)也為我們制作自定義插件提供有力的參考。首先,不同插件的JS代碼都是單獨(dú)放在一個(gè)JS文件中的,開發(fā)人員在使用的時(shí)候可以一次性編譯到Bootstrap.js,也可以單獨(dú)使用某一個(gè)或者多個(gè)JS插件文件。唯一需要注意的是:有些JS插件依賴于其他JS插件,所以不要遺漏了依賴引用。Bootstrap所有的JavaScript插件都可以通過配置使用,即通過特定的HTML設(shè)置,而不需要任何JavaScript再次觸發(fā)。但如果需要啟用手動(dòng)觸發(fā)事件的行為,可以禁用默認(rèn)的行為,禁用方法非常簡(jiǎn)單,只需要將body元素上的命名空間為data-api下的全部事件禁用即可。代碼如下所示:
如果想禁用特定插件的默認(rèn)行為,只需要禁用該插件所在命名空間下的事件即可。代碼如下所示:
注意off語法是jQuery提供的語法功能,用戶在使用on進(jìn)行綁定事件的時(shí)候,可以加命名空間,比如
這樣在卸載事件的時(shí)候,如果只想卸載該元素的該特定事件,可以使用off('click.alert.data-api')。如果不這樣,僅僅使用off('click'),這樣該元素上的所有click事件都將被卸載(導(dǎo)致該元素的其他click事件失效)。同理,如果執(zhí)行off('.data-api')代碼,則所有在data-api命名空間下的事件都會(huì)被卸載禁用,不管是該選擇器內(nèi)部的哪個(gè)元素、哪種事件。
1.可編程性所有的插件不僅可以使用聲明式定義(HTML),也可以通過JavaScript代碼全部實(shí)現(xiàn)。利用jQuery的鏈?zhǔn)讲僮?,編出的代碼非常優(yōu)美。示例如下所示:
所有的插件在使用JavaScript代碼調(diào)用的時(shí)候,都提供多種調(diào)用方式:無參數(shù)傳遞(即默認(rèn)方式)、傳遞對(duì)象字面量進(jìn)行初始化參數(shù)設(shè)定、直接傳入一個(gè)需要執(zhí)行的方法名稱字符串。示例如下所示:
每個(gè)插件都有一個(gè)Constructor屬性,用于表示原始的構(gòu)造函數(shù),比如$.fn.alert.Constructor。另外也可以通過$('選擇符').data('bs.插件名稱')的形式(如,$('[datadismiss="alert"]').data('bs.alert'))獲取該特定插件的實(shí)例。
2.防沖突和jQuery一樣,Bootstrap插件可以和其他同類插件共存,為了防止$.fn.下的Bootstrap插件被覆蓋,Bootstrap也提供了防沖突功能(No conflict),用于定義別名。示例用法如下:
3.自定義事件Bootstrap為很多插件都提供了自定義事件功能,比如,modal彈窗里提供的show和shown事件,show事件在彈窗初始化(即將彈出)的時(shí)候觸發(fā),而shown事件則是在彈窗初始化完畢后(完全彈出)才觸發(fā)。在新版插件里,所有的事件都是命名空間化的,即單個(gè)事件都要放在某個(gè)命名空間下,比如,show.bs.modal。所有的插件都提供了preventDefault功能,用于阻止繼續(xù)執(zhí)行后續(xù)的代碼。例如,可以在modal彈窗的show事件里進(jìn)行判斷,如果不符合條件就拒絕顯示彈窗。示例代碼如下所示:
$('#myModal').on('show.bs.modal', function (e) { if (!data) return e.preventDefault() // 拒絕顯示彈窗})