BootStrap--整體框架--JavaScript插件架構

1. JavaScript插件架構

如下是插件alert的全部代碼,每個插件都定義在如下類似的作用域中:

+function ($) {
  'use strict';

  // ALERT CLASS DEFINITION
  // ======================

  var dismiss = '[data-dismiss="alert"]'
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }

  Alert.VERSION = '3.3.7'

  Alert.TRANSITION_DURATION = 150

  Alert.prototype.close = function (e) {
    var $this    = $(this)
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = $(selector === '#' ? [] : selector)

    if (e) e.preventDefault()

    if (!$parent.length) {
      $parent = $this.closest('.alert')
    }

    $parent.trigger(e = $.Event('close.bs.alert'))

    if (e.isDefaultPrevented()) return

    $parent.removeClass('in')

    function removeElement() {
      // detach from parent, fire event then clean up data
      $parent.detach().trigger('closed.bs.alert').remove()
    }

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


  // ALERT PLUGIN DEFINITION
  // =======================

  function Plugin(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)
    })
  }

  var old = $.fn.alert

  $.fn.alert             = Plugin
  $.fn.alert.Constructor = Alert


  // ALERT NO CONFLICT
  // =================

  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }


  // ALERT DATA-API
  // ==============

  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

//通過將作用域內的Alert類賦值給jQuery的alert對象的Constructor屬性,在IIFE作用域外也可以使用Alert類,比如這行代碼
var Alert = $.fn.alert.Constructor  

BootStrap所有的插件在開發中都遵循了同樣的規則,也爲自定義插件提供了規範和依據(如下三個規則):
1.HTML佈局規則:基於元素自定義屬性的佈局規則,比如使用類似於data-target的自定義屬性
2.JavaScript實現步驟(所有插件都遵循jQuery插件開發的標準步驟,所有事件保持統一的標準)
3.插件調用方法(插件使用方式可以是HTML聲明式或者調用式)

1.1 HTML佈局規則

基於元素自定義屬性的佈局規則,類似於data-* 的自定義屬性

默認情況下,所有插件都可以通過設置特定的HTML代碼和相應的自定義屬性來實現。
在頁面加載的時候,js代碼會自動檢測到這些標記,並自動綁定相應的事件,不需要添加額外的代碼。

點擊按鈕之後就會關閉警告框:

<div class="alert">
    <button type="button" class="close" data-dismiss="alert"></button>
    <strong>警告!</strong>你輸入的項目不合法!
</div>

下拉菜單:在button按鈕上添加data-toggle=”dropdown”屬性,單機按鈕時,默認隱藏的dropdown-menu會顯示

//例子:下拉菜單.html
<div class="btn-group">
    <button type="button" class="btn btn-default" data-toggle="dropdown">
        我的書籍<span class="caret"></span>
    </button>
    <ul class="dropdown-menu">
        <li><a href="#">編程</a></li>
        <li><a href="#">設計</a></li>
        <li><a href="#">深入</a></li>
    </ul>
</div>
1.2 JavaScript實現步驟(所有插件都遵循jQuery插件開發的標準步驟,所有事件保持統一的標準)

BootStrap中所有JavaScript插件走遵循統一的實現步驟,維護方便,自定義插件也方便,步驟如下:

1.聲明立即調用函數,比如+function($){“use strict”;…}(jQuery);

參數中傳入jQuery的對象,通過參數1. 符變量代表了局部變量,而不是全局變量中代表jQuery的2. .fn上設置了插件(比如.fn.alert=) 符變量才能將整個插件通過唯一的藉口$.fn.alert暴露出去,從而保護了內部代碼。

//function前邊的+,主要目的是防止前面有未正常結束的代碼(比如遺漏了分號),導致前後代碼被編譯器認爲是一體的,從而導致代碼運行出錯。
+function($){
    "use strict";

}(window.jQuery);

2.定義插件類(或者選擇器)以及相關原型方法。比如Alert,prototype.close

定義插件類Alert,然後在定義一些原型函數,比如close函數方法。
先定義選擇器,所有符合該自定義屬性的元素可以觸發下面的事件。

var dismiss = '[data-dismiss="alert"]';
var Alert = function(el) {
    //傳入元素,如果元素內部有dismiss上設置的自定義屬性,則click事件會觸發原型上的close方法
    $(el).on('click',dismiss,this.close);
};
Alert.prototype.close = function(e) {

}

3.在jQuery上定義插件並重設插件構造函數,例如$.fn.alert.Constructor=Alert

在jQuery上定義插件,以便通過jQuery.插件名稱的方式,也能夠使用該插件。

function Plugin(option) {
  return this.each(function () {
    var $this = $(this)
    //獲取存儲的Alert對象,如果是第一次執行變量data的值爲undefined  
    var data  = $this.data('bs.alert')
    //緩存沒有,就new一個alert對象,存儲在元素的jQuery對象上的‘bs.alert’數據字段
    if (!data) $this.data('bs.alert', (data = new Alert(this)))
    //支持傳入方法名參數,執行該方法,這裏就是data.close()
    if (typeof option == 'string') data[option].call($this)
  })
}
//jQuery插件的定義使用了標準的方式,在fn上進行擴展,在jQuery上定義alert插件
//保留其他插件的$.fn.alert代碼(如果定義)以便在noConflict之後,可以繼續使用改舊代碼
//先備份之前插件的舊代碼,以便在後面防衝突的時候使用
var old = $.fn.alert

$.fn.alert             = Plugin
//在附加擴展之後,重新設置插件的構造器(即Constructor屬性),這樣就可以通過Constructor屬性查詢到插件的真實類函數,使用new操作符實例化的時候也不會出錯
//js區分大小寫,所以這裏的Constructor只是一個普通屬性,跟constructor不同,通過將作用域內的Alert類賦值給jQuery的alert對象的Constructor屬性,在IIFE作用域外也可以使用Alert類
$.fn.alert.Constructor = Alert

不聲明第三步的話,HTML聲明式的方式也是可以用的。所以第三步是專門爲某些喜歡用js代碼觸發事件的人所準備的。需要注意的是,如果第三步不需要,第四步的方衝突的功能也就沒辦法用了~

4.防衝突處理(noConflict),例如$.fn.alert.noConflict

目的是讓BootStrap插件和其他UI庫的同名插件並存。

$.fn.alert.noConflict = function() {
    //恢復以前的代碼
    $.fn.alert = old
    //將$.fn.alert.noConflict()設置爲BootStrap的alert插件
    return this
}

比如A庫中有個同名.fn.alertBootStrapold .fn.alert.noConflict後就會還原該old對象插件
而使用BootStrap的alert插件的話,則通過var alert = $.fn.alert.noConflict()的形式,將BootStrap的alert插件轉移到另外一個變量上,從而繼續使用。

5.綁定各種觸發事件(data-api)

由於已經爲jQuery提供了默認的$.fn.alert擴展插件功能,就可以手工編寫js代碼來觸發事件了。
這裏主要是爲聲明式的HTML觸發事件。即:在HTML文檔裏已經按照佈局規則聲明瞭相關的自定義屬性(比如data-dismiss=”alert”),然後通過這裏的代碼初始化默認的單擊事件行爲。

/*
ALERT DATA-API
這段JavaScript代碼將click委託事件監聽器綁定在document元素上,並給click事件賦予命名空間
jQuery將事件綁定在document文檔對象上的好處,就是js事件代理的優點
 */
$(document).on('click.bs.alert.data-api',dismiss,Alert.prototype.close)

命名空間的話好處:
http://suqing.iteye.com/blog/1533123

1.3 插件調用方法(插件使用方式可以是HTML聲明式或者調用式)

1.插件可以js代碼調用,都提供多種調用方式(無參數傳遞,傳遞對象字面量,直接傳入一個需要執行的方法名稱字符串)

$("#myModal").modal();
$("#myModal").modal({keyboard:false});
$("#myModal").modal('show');

每個插件都有一個Constructor屬性,表示原始的構造函數,比如fn.alert.Constructor (‘選擇器’).data(‘bs.插件名稱’)獲取特定插件的實例

2.html聲明式就是直接在html中進行聲明data-* 自定義屬性即可

若想禁用方法

//命名空間爲data-api的全部事件禁用
$(document).off('.data-api');
//禁用特定插件的默認行爲,禁用該插件所在命名空間下事件即可
$(document).off('.alert.data-api');
//禁用該alert插件的click事件
$(document).off('click.alert.data-api');
發佈了198 篇原創文章 · 獲贊 18 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章