1、Bootstrap的作用域
2、Bootstrap的類定義
3、Bootstrap的插件定義
4、Bootstrap的事件代理
5、Bootstrap的對象數(shù)據(jù)緩存
6、Bootstrap的防沖突
7、作用域外如何使用Button類
8、Bootstrap的單元測試
Bootstrap的作用域
Bootstrap每個插件都定義在下面這段作用域代碼中:
- +function ($) {
- ...
- }(window.jQuery)
請看《 IIFE》和《 嚴(yán)格模式》編譯環(huán)境。
在插件的作用域之外,全局范圍執(zhí)行代碼的第一行,檢測了jQuery是否定義。在Grunt的concat任務(wù)中,合并所有插件時,檢測代碼添加在目標(biāo)文件的banner說明后面。Grunt.js的相關(guān)代碼:
- jqueryCheck: 'if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") }\n\n',
-
- concat: {
- options: {
- banner: '<%= banner %><%= jqueryCheck %>',
- stripBanners: false
- },
- bootstrap: {
- src: [
- 'js/transition.js',
- 'js/alert.js',
- 'js/button.js',
- 'js/carousel.js',
- 'js/collapse.js',
- 'js/dropdown.js',
- 'js/modal.js',
- 'js/tooltip.js',
- 'js/popover.js',
- 'js/scrollspy.js',
- 'js/tab.js',
- 'js/affix.js'
- ],
- dest: 'dist/js/<%= pkg.name %>.js'
- }
- }
Bootstrap的類定義
- var Button = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Button.DEFAULTS, options)
- }
-
- Button.DEFAULTS = {
- loadingText: 'loading...'
- }
-
- Button.prototype.setState = function (state) {
- ...
- }
-
- Button.prototype.toggle = function () {
- ...
- }
Bootstrap采用這種類定義方式的好處,以及Javascript其他幾種類定義的方式,請參照《Javascript面向?qū)ο缶幊蹋ㄒ唬悍庋b》
Javascript規(guī)定,每一個構(gòu)造函數(shù)都有一個prototype屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構(gòu)造函數(shù)的實例繼承。這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype對象上。在Button函數(shù)體內(nèi)部定義的屬性和方法可以看做是類的私有屬性和方法, 為Button.prototype對象定義的屬性和方法都可以看做是類的公共屬性和方法。這個類封裝了插件對象初始化所需的方法和屬性。
Bootstrap的插件定義
請參看《jQuery插件開發(fā)快速入門》,注意兩個this指向的是不同對象
- $.fn.button = function (option) {
- return this.each(function () {
- var $this = $(this)
- ...
- })
- }
Bootstrap的事件代理
Bootstrap Button插件定義最后一部分,事件綁定是這么寫的
- $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
- ...
- })
這段JavaScript代碼將click委托事件監(jiān)聽器綁定在document元素上,并給click事件賦予命名空間click.bs.button.data-api,選擇器匹配的是屬性data-toggle的值為"button"開頭的標(biāo)簽。
關(guān)于jQuery將事件綁定在document文檔對象上的好處,就是js事件代理的優(yōu)點,性能上做了一個測試比較。
關(guān)于jQuery命名空間的好處,請參看《jQuery .on() and .off() 命名空間》
Bootstrap的防止沖突
jQuery是全局對象,所以jQuery的插件定義$.fn.button并不受作用域限制。如果在別的插件中同樣定義了button插件,后加載的button插件將會覆蓋先加載的button插件,jsbin示例:
- // Old button
- +function($){
- $.fn.button = function() {
- alert('Old button')
- }
- }(window.jQuery)
-
- // Bootstrap button
- +function($){
- $.fn.button = function() {
- alert('Bootstrap button')
- }
- }(window.jQuery)
-
- $('a').button() // alert('Bootstrap button')
Bootstrap做了插件沖突處理, jsbin示例:
- // Old button
- +function($) {
- $.fn.button = function() {
- alert('Old button')
- }
- }(window.jQuery)
-
- // Bootstrap button
- +function($){
- // 將原先的button插件對象賦值給一個臨時變量old
- var old = $.fn.button
-
- $.fn.button = function() {
- alert('Bootstrap button')
- }
-
- // 執(zhí)行該函數(shù),恢復(fù)原先的button定義,并返回Bootstrap定義的button插件
- $.fn.button.noConflict = function () {
- $.fn.button = old
- return this
- }
-
- }(window.jQuery)
-
- // <span style="font-family: Helvetica, Tahoma, Arial, sans-serif; white-space: normal; background-color: #ffffff;">作用域</span>外我們可以靈活使用兩個button插件
- $.fn.button = $.fn.button.noConflict()
- $('a').button() // alert('Bootstrap button')
-
- $.fn.button.noConflict()
- $('a').button() // alert('Old button')
Bootstrap作用域外如何使用Button類
- $.fn.button.Constructor = Button
在Bootstrap的button插件中還有上面者句代碼,去掉它不影響插件的正確執(zhí)行。
它很像javascript中類構(gòu)造器:
- var Cat = function(name) {
- this.name = name
- }
- var cat1 = new Cat('Hello Kitty')
- var cat2 = new Cat('Doramon')
-
- cat1.constructor == Cat.prototype.constructor
但是Javascript是區(qū)分大小寫的,也就是 這里大寫開頭的的Constructor 和 Javascript小寫開頭的constructor 沒有任何關(guān)系。
查找jQuery源碼中也沒有對于大寫開頭的Constructor的定義。所以這里的Constructor只是一個普通屬性,我們也可以寫成其他名字 $.fn.button.Something = Button,Bootstrap為了指明這個屬性的意義而命名為構(gòu)造器“Constructor”更合理。
這樣一來,這段代碼就很好理解了:$.fn.button.Constructor = Button 通過將作用域內(nèi)的Button類賦值給jQuery的button對象的Constructor屬性,在IIFE作用域外也可以使用Button類。調(diào)用方式:
- +function($){
- // 類定義
- var Button = function() {}
- // 插件定義
- $.fn.button = function() {
- alert('Bootstrap button')
- }
- // 類賦值到j(luò)Query button對象的Constructor屬性
- $.fn.button.Constructor = Button
-
- }(window.jQuery)
-
- var Button = $.fn.button.Constructor
Bootstrap的對象數(shù)據(jù)緩存
- // 獲取存儲的Button對象,如果是第一次執(zhí)行變量data的值為undefined
- var data = $this.data('bs.button')
- var options = typeof option == 'object' && option
-
- // 創(chuàng)建Button對象: new Button(this, options),
- // 并賦值給變量data: data = new Button(this, options)
- // 存儲在元素的jQuery對象上的‘bs.button’數(shù)據(jù)字段 $this.data('bs.button', data)
- if (!data) $this.data('bs.button', (data = new Button(this, options)))
-
- // data是一個Button對象,可以調(diào)用Button的原生方法
- if (option == 'toggle') data.toggle()
- else if (option) data.setState(option)
利用jQuery的 .data(key, value)存儲Button對象
Bootstrap的單元測試
QUnit + PhantomJS
優(yōu)秀的程序猿有一個共同的秘訣:閱讀優(yōu)秀的代碼。
|