像bootstrap一樣的去做web程式設計

edithfang發表於2014-12-31
1: 閉包

boot的閉包方式有點特別,普通的閉包是這樣的:

(function ($) {
 
})(jQuery)


這種寫法是怕全域性汙染,把$封閉在自己的空間裡,暴露在外面的只有jQuery,這樣,如果用了別的也用$的控制元件,就可以避免衝突。

而boot的閉包又有一些不同:

+function ($) {
 
}(jQuery)


這樣寫除了之前的好處,還有一點就是簡潔,以及更重要的一點,避免之前的括號沒有閉合,導致的衝突。這樣,更加的獨立,之前的包沒有閉合也不會影響到這裡。就好像保守的程式設計師,喜歡在個別的語句前,多家一個";",為的就是怕之前的語句與現在的語句合在了一起。

2:衝突的避免

除了控制jQuery中$的衝突,還要避免外掛重名所帶來的衝突。

jQuery 有自己的避免$全域性汙染的方法,就是noConflict。他可以把變數過渡到別的符號上,或者只是把$收回,只暴露出jQuery來。

而boot自己也有類似的衝突解決方法。

下面是所有boot外掛的格式,以alert為例:

+function($){
 
 var old = $.fn.alert;
 
 $.fn.alert = function (option) {}
 
 $.fn.alert.Constructor = Alert;
 
 $.fn.alert.noConflict = function () {
 $.fn.alert = old;
 return this;
 }
 
}(jQuery)

這樣接入有一個別的alert控制元件,也叫做alert。那麼我們就會把他儲存到old裡。然後在把他重新生命為自己的alert控制元件。

如果在接下來,我們需要用之前的alert,那麼就noConflict一下,這樣,alert就又付給了之前的alert控制元件,也就是old。

再把我們們自己寫的alert返回出來。我們可以再給他付給別的空間名,這樣兩個就都可以用了。

而且我們也可以用Constructor來檢視現在alert究竟是哪個控制元件。

3:on的使用

boot很方便,有些控制元件是自動的繫結在了特定的元素上的。還是以alert為例。
 
var dismiss = '[data-dismiss="alert"]'
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close);


這裡就是on的用法,他可以監聽整個document,然後在根據引數,冒泡到特定的元素上去,這樣做的好處是,可以再元素未被渲染的情況下,就把事件繫結到上面去,這樣做,不用ready,也可以對新生成的元素執行同樣的事件。所以boot的空間,除了特定的一些(比如tooltip),都可以在寫出來的同時,就可以應用,只需要給元素特定的屬性。

4:css3的相容解決方案

有時候,我們需要在動畫效果結束後在來去呼叫一些函式,在我們用jquery的動畫時,animate的done引數可以幫我們很好地解決這方面的事情,可是當我們的大部分動畫,都應用了css3的時候,要怎麼辦呢。所以boot'用了 一下這個方法:

+function ($) {
 'use strict';
 
 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
 // ============================================================
 
 function transitionEnd() {
 var el = document.createElement('bootstrap')
 
 var transEndEventNames = {
 WebkitTransition : 'webkitTransitionEnd',
 MozTransition : 'transitionend',
 OTransition : 'oTransitionEnd otransitionend',
 transition : 'transitionend'
 }
 
 for (var name in transEndEventNames) {
 if (el.style[name] !== undefined) {
 return { end: transEndEventNames[name] }
 }
 }
 
 return false // explicit for ie8 (  ._.)
 }
 
 // http://blog.alexmaccaw.com/css-transitions
 $.fn.emulateTransitionEnd = function (duration) {
 var called = false
 var $el = this
 $(this).one('bsTransitionEnd', function () { called = true })
 var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
 setTimeout(callback, duration)
 return this
 }
 
 $(function () {
 $.support.transition = transitionEnd()
 
 if (!$.support.transition) return
 
 $.event.special.bsTransitionEnd = {
 bindType: $.support.transition.end,
 delegateType: $.support.transition.end,
 handle: function (e) {
 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
 }
 }
 })
 
}(jQuery);

他首先去問瀏覽器,是否支援transitionend這個屬性,如果支援,那麼我們在來做後續的操作,同樣以alert為例:

$.support.transition && $parent.hasClass('fade') ?
 $parent
 .one('bsTransitionEnd', removeElement)
 .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
 removeElement()


首先$.support.transition,呼叫transitionEnd方法,看看是否支援這個屬性,如果支援,那麼就用one註冊一次 transitionend,然後在用emulateTransitionEnd去呼叫一下,引數為這個css3動畫的時間duration。這個時間之後去呼叫這次事件,就可以達成callback的形式。當然如果不支援這個屬性,那麼我們就直接執行callback,就ok了。

5:trigger的應用

trigger可以手動的觸發事件,以modal控制元件為例,在之前的版本的控制元件中,當modal框彈出來的時候,底部主視窗的滾動條沒有取消,所以在後續的控制元件中(大概3.0.3左右),用了自身的註冊事件來避免這部分的小bug。程式碼如下:
 
$(document)
 .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
 .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })


他在每次點開modal框之前,也就是show事件中,給body新增class:modal-open,這個樣式把overflow給hidden掉。再在關閉modal框之後,也就是hidden事件中,再把這個class給remove掉。

這裡註冊了時間,那麼哪裡去觸發呢?這就用到了trigger方法,在特定的地方

 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
 that.$element.trigger(e)


這樣就觸發了事件。大部分的外部介面就是這樣給出的。

6:事件登出的技巧

boot在事件註冊的時候給了很多的字尾。比如 click.bs.alert,show.bs.modal。這樣做事為了什麼呢。

加入我想取消掉alert的click事件。可是我不能把所有的click事件都取消掉,所以我們在off事件的時候,就要這樣寫:

$(document).off('click.bs.alert')

如果我想登出掉全部的alert的事件,那麼就要:

$(document).off('.bs.alert')

同理,要是想登出掉全部的boot註冊的時間 那麼就要:

$(document).off('.bs')

所以在註冊時間時候,才要麻煩的加字尾,是為了我們之後的行為做準備的。這樣寫非常的有道理。

7:api的使用

boot給了我們簡單的介面,但是沒有給我們全部,可是其實我們是可以拿到的。

boot把方法給了data。如下面:

$.fn.alert = function (option) {
 return this.each(function () {
 var $this = $(this)
 var data = $this.data('bs.alert')
 
 if (!data) $this.data('bs.alert', (data = new Alert(this)))
 if (typeof option == 'string') data[option].call($this)
 })
 }


在alert的時候,首先檢查元素中用沒有alert這個data,有的話,則直接呼叫,沒有的話才生成新的。

那麼其實我們可以這樣做:
$('.alert').alert();
var api = $('.alert').data('bs.alert');
api.hide();
這是和$('.alert').alert('hide');一樣用的。

8:proxy的應用

proxy呼叫一個方法,切用引數取代方法中的this,好像我自己寫的控制元件form就有這麼一段:

this.$element.on('click','[data-formtype="reset"]',$.proxy(function () {
 this.reset();
 }, this));
我用了$element冒泡到的data-formtype=reset的元素,那麼this自然指向了它,它的click事件是呼叫方法本身的reset()事件,可是裡面的this不是這個方法,那麼我們就用proxy來指向當前方法的this。這個方法靈活運用,對於封裝控制元件有很大作用。

如果哪裡寫的不對,希望得到指正,大家一起交流。
評論(2)

相關文章