先看bootstrap.button.js的結構
var Button = function ( element, options ){} //構造器 Button.prototype = {} //構造器的原型 $.fn.button = function ( option ){} //jQuery原型上的自定義方法 $.fn.button.defaults = {} //默認參數 $.fn.button.Constructor = Button //重寫jQuery原型自定義方法的構造器名 $(function (){}) // 初始化
HTML結構
<table class="table table-bordered table-striped"> <tbody> <tr> <td>狀態</td> <td><button id="fat-btn" class="btn btn-primary" data-loading-text="loading..."> 載入狀態 </button></td> </tr> <tr> <td>單獨開關</td> <td><button class="btn btn-primary" data-toggle="button">單獨開關</button></td> </tr> <tr> <td>復選</td> <td> <div class="btn-group" data-toggle="buttons-checkbox"> <button class="btn btn-primary">左</button> <button class="btn btn-primary">中</button> <button class="btn btn-primary">右</button> </div> </td> </tr> <tr> <td>單選</td> <td> <div class="btn-group" data-toggle="buttons-radio"> <button class="btn btn-primary">左</button> <button class="btn btn-primary">中</button> <button class="btn btn-primary active">右</button> </div> </td> </tr> </tbody> </table>
這個例子有點問題,因為初始化時,第一個按鈕沒有綁定事件,所以第一個按鈕不可用,不過沒關系,讀完源碼之后,我們嘗試將它補全。
/* * 初始化 * 這里初始化了擁有data-toggle^='button'屬性的對象,注意^,只要存在button字符串就可以匹配成功。 * */ $(function () { $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { var $btn = $(e.target) if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') $btn.button('toggle')//進入jQuery的原型方法button中 }) })
像單獨一個開關,直接本身就有btn類,像單選按鈕,觸發的是div里面的button,尋找最近的擁有.btn類的對象,就是自己。進入jQuery原型的button方法中。
/* * jQuery原型上的自定義方法 * */ $.fn.button = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('button') , options = typeof option == 'object' && option if (!data) $this.data('button', (data = new Button(this, options)))//實例化構造器 if (option == 'toggle') data.toggle() //執行toggle方法 else if (option) data.setState(option) }) }
初始化,傳入參數為toggle,默認執行原型上的toggle方法。先實例化
/* * 構造器 * */ var Button = function ( element, options ) { this.$element = $(element) this.options = $.extend({}, $.fn.button.defaults, options)//合並默認參數 }
進入原型上的toggle方法
toggle: function () { var $parent = this.$element.parent('[data-toggle="buttons-radio"]') //如果父節點有該屬性,則表示只能允許 //一個按鈕顯示被按效果 /* * 跟之前總結的方式,先所有刪除,最后那個點擊那個顯示效果 * */ $parent && $parent .find('.active') .removeClass('active') this.$element.toggleClass('active')//核心方法,通過active類樣式控制btn的顯示效果 }
核心竟是jQuery的toggleClass方法。。這里做了一個特例區分,如果父類有data-toggle='buttons-radio'屬性的,只能有一個按鈕有特殊樣式,這個邏輯之前我們已經在別的插件中總結了。上述的代碼也是用的這個邏輯。
ok,回到我們開始的問題,第一個按鈕不能使用,那是我們沒有綁定事件,在我們動手做之前,先大致看一下原型上的另一個方法setState
setState: function ( state ) { var d = 'disabled' , $el = this.$element , data = $el.data() , val = $el.is('input') ? 'val' : 'html'//如果是input,采用val()方取值,不是則使用html()方法 state = state + 'Text' data.resetText || $el.data('resetText', $el[val]()) //console.log(this.options[state]); $el[val](data[state] || this.options[state]) // push to event loop to allow forms to submit setTimeout(function () { state == 'loadingText' ? $el.addClass(d).attr(d, d) : $el.removeClass(d).removeAttr(d); }, 0) }
如果我們獲取第一個按鈕的jQuery對象,調用button方法,必須要傳參數,不傳的話,不執行。詳情可以回看它的button方法的定義。
else if (option) data.setState(option)//需要傳值
傳什么值,隨便傳么,試一下不行,重新看setState方法。它將形參與字符串'Text'相加,最后將其作為屬性名去查找對象值,再看看$el.data()里的內容(默認參數和HTML結構)
<button id="fat-btn" class="btn btn-primary" data-loading-text="loading..."> 載入狀態 </button>
data中有個loadingText屬性,注意這里需要用駝峰命名。那我們傳入的值就為loading了。實驗一下,完全可以。
至於最后在setState方法中加入定時器,本人覺得寫的很蛋疼。loading的過程,是等待服務器響應並將處理結果返回給瀏覽器,一般考慮ajax實現,不過讀者可以根據自己的需求,自行修改,沒有最好的代碼,只有更強的coder。
上面的部分樣式,大家可以參考bootstrap.css 去查看,比較簡單。
內容不多,時間剛好,以上是我的一點讀碼體會,如有錯誤,請指出,大家共通學習。