bootstrap插件學習-bootstrap.collapse.js


 

先看bootstrap.collapse.js的結構

var Collapse = function ( element, options ){} // 構造器
Collapse.prototype = {} //構造器的原型
$.fn.collapse = function ( option ){} //jQuery原型上自定義的方法
$.fn.collapse.defaults = {} // 默認參數
$.fn.collapse.Constructor = Collapse // 重寫jQuery原型自定義方法的構造器名
$(function (){}) // 初始化

HTML結構

<div class="accordion" id="accordion2">

     <div class="accordion-group">

       <div class="accordion-heading">

         <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseOne">

           國土問題

         </a>

       </div>

       <div id="collapseOne" class="accordion-body collapse" style="height: 0px;">

         <div class="accordion-inner">

   前一段時間一個段子說,某國的網民在因國土問題與中國網民爭吵時說,我要打到北京,中國的網民非常淡然地回應,就你那經濟水平,交得起過路費嗎?這兩天新的段子說,李白要是活在今天的話,估計一大半以上他的詩根本寫不出來,因為名山大川的門票他根本買不起。

         </div>

       </div>

     </div>

     <div class="accordion-group">

       <div class="accordion-heading">

         <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseTwo">

           門票問題

         </a>

       </div>

       <div id="collapseTwo" class="accordion-body collapse" style="height: 0px;">

         <div class="accordion-inner">

   目前,中國半數5A級景區門票達到100元,黃山門票10年來由80元漲至230元。山東曲阜稱,與同類景區相比收費較低,僅收150元,不漲票價就丟身價。曲阜的孔廟、孔府和孔林,年收入1.5億元左右,全部上繳了地方財政,但景區維護成本從未公開。

         </div>

       </div>

     </div>

     <div class="accordion-group">

       <div class="accordion-heading">

         <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseThree">

           超生罰款

         </a>

       </div>

       <div id="collapseThree" class="accordion-body in" style="height: auto;">

         <div class="accordion-inner">

   學者楊支柱因生二胎被取消公職,並罰款24萬余元。他稱,計生罰款以前直接叫超生罰款,入世后改成"社會撫養費"。根據9省市超生罰款的平均數,全國31個省市每年征收的超生罰款可高達279億元。其中大城市將該收入上繳財政,而地方則分配混亂,部分罰款去向成謎。

         </div>

       </div>

     </div>

   </div>

我們先從初始化開始

/*
  * 初始化
  * */
  $(function () {
    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {

      var $this = $(this), href
        , target = $this.attr('data-target')//標題沒有data-target屬性,阻止冒泡
          || e.preventDefault()
          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
          //根據點擊的標題,獲取相對應內容的id
        , option = $(target).data('collapse') ? 'toggle' : $this.data()//初次執行時$(target)沒有collapse屬性
      $(target).collapse(option)
    })
  })

body監聽了所有擁有data-toggle='collapse'屬性的標簽,為它們綁定了click事件,在HTML中由於標簽上都沒有data-target屬性,所以該事件被阻止冒泡,最后獲得點擊標題框所對應的內容div的id。

當我們刷新頁面,第一次點擊時,由於$(target).data('collapse')為空,所以option為$this.data()的內容,主要有{parent:'#accordion2',toggle:'collapse'},下面執行jQuery對象上的collapse方法

/*
  * jQuery原型上自定義的方法
  * */
  $.fn.collapse = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('collapse')
        , options = typeof option == 'object' && option
      if (!data) $this.data('collapse', (data = new Collapse(this, options)))//實例化構造器
      if (typeof option == 'string') data[option]()//支持傳入方法名,執行該方法
    })
  }

此時調用collapse方法的是你點擊標題框所對應的內容div,這里我們需要初始化構造器。因為option此時為對象,所以最后一句不執行。

/*
  * 構造器
  * */
  var Collapse = function ( element, options ) {
      this.$element = $(element)
    this.options = $.extend({}, $.fn.collapse.defaults, options)
    if (this.options["parent"]) {
      this.$parent = $(this.options["parent"])//獲取整個控件的jQuery對象
    }
    this.options.toggle && this.toggle()//實例化執行原型上的toggle方法
  }

這里this.$parent指的是整個控件的div,id為'#accordion2',執行原型上的toggle方法

toggle: function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()//實例化初次執行show方法
      }

這里,查看內容div上是否有in類,其實bootstrap.collapse插件,在顯示的內容上,會有in類,不顯示的內容上會collapse類,不過,之前我們先了解。這個插件刷新時,第三塊內容顯示,ok,我們點擊第一塊試一試。,那么第一塊對應的內容div就沒有in類,所以我們執行show方法,在進入方法之前,我們可以想想下面插件需要完成的步驟:1。將之前顯示的隱藏了 2.顯示被點擊的

/*
    * 顯示方法
    * */
  , show: function () {
      var dimension = this.dimension()
        , scroll = $.camelCase(['scroll', dimension].join('-')) //'scrollHeight'
        , actives = this.$parent && this.$parent.find('.in')//刷新時,顯示內容的div,默認設置的
        , hasData
      if (actives && actives.length) {
        //console.log(actives.data('collapse'));
        hasData = actives.data('collapse')
        actives.collapse('hide')//將開始顯示的內容隱藏了,調用hide方法。
        hasData || actives.data('collapse', null)
      }

      this.$element[dimension](0)//將高度清0,完成隱藏效果
      this.transition('addClass', 'show', 'shown')
      this.$element[dimension](this.$element[0][scroll])//將當前點擊的標簽相關聯的內容的高度恢復,結果顯示效果

    }

查看show方法之前,我們先看dimension方法

dimension: function () {
      var hasWidth = this.$element.hasClass('width')
      return hasWidth ? 'width' : 'height'
    }

主要返回字符串,這個插件主要是上下顯示隱藏,也可以左右隱藏。這里我們返回height

scroll = $.camelCase(['scroll', dimension].join('-')) //'scrollHeight'

目的將scroll與height兩個字符串合並成scrollHeight。這種方式,我們可以了解一下。

actives = this.$parent && this.$parent.find('.in')//刷新時,顯示內容的div,默認設置的

找到頁面上目前顯示的內容對象,經過if判斷之后,這個內容對象調用了jQuery原型上的collapse方法。參數為hide,我們再次進入jQuery原型方法

/*
  * jQuery原型上自定義的方法
  * */
  $.fn.collapse = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('collapse')
        , options = typeof option == 'object' && option
      if (!data) $this.data('collapse', (data = new Collapse(this, options)))//實例化構造器
      if (typeof option == 'string') data[option]()//支持傳入方法名,執行該方法
    })
  }

這里的$this.data('collapse')是沒有,這個跟之前的要區分開來,之前的是你點擊的想讓它顯示的內容,而現在這個是頁面上原來就顯示的內容。所以再一次的實例化。options內容為false。別忘了,執行完初始化之后再執行data[option],先看構造器

/*
  * 構造器
  * */
  var Collapse = function ( element, options ) {
      this.$element = $(element)
    this.options = $.extend({}, $.fn.collapse.defaults, options)
    if (this.options["parent"]) {
      this.$parent = $(this.options["parent"])//此時已經沒有該對象了
    }
    this.options.toggle && this.toggle()//實例化執行原型上的toggle方法
  }

記住此時實例化的對象是當前顯示的div內容。假如我們點擊的是第一個標題對應的div,默認顯示是第三個div,那這時實例化的對象就是第三個div。下面的代碼分析,我們就這套看。

toggle: function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()//實例化初次執行show方法
      }

此時的this.$element上已經擁有了in類,畢竟它是默認顯示的嘛,執行原型上的hide方法。

/*
    * 隱藏方法
    * */
  , hide: function () {
var dimension = this.dimension()
      this.reset(this.$element[dimension]())
      this.transition('removeClass', 'hide', 'hidden')
      this.$element[dimension](0)//將高度清0
    }

dimension這個就不重復說了,進入reset方法

reset: function ( size ) {
      var dimension = this.dimension()
      this.$element.removeClass('collapse')[dimension](size || 'auto')[0].offsetWidth//這句蛋疼
      this.$element[size ? 'addClass' : 'removeClass']('collapse')//給要隱藏的內容div加上collapse樣式

      return this
    }

想一想之前我們點擊第一個div,目的是讓它顯示,隱藏其他div。這邊調用reset方法的是div3,根據它的高度,增加collapse,前面我們也說了,bootstrap.collapse插件在隱藏的div上都加有collapse類,顯示的div上都有in類,因為reset方法是根據高度來判斷是否要添加class,所以在代碼后面也肯定會將高度清0的,為的是依靠判斷再次刪去class,但是感覺這個方式太繁瑣,通過高度判斷,刪減css讓div隱藏,在將div的高度清0,再通過高度判斷,向div上刪減css樣式,使其顯示,最后在恢復div的高度。如此反復。

不多廢話,進入transition方法

transition: function ( method, startEvent, completeEvent ) { //'removeClass','hide','hidden'
           var that = this
        , complete = function () {
            if (startEvent == 'show') that.reset()
            that.$element.trigger(completeEvent)
          }

      this.$element
        .trigger(startEvent)
        [method]('in')//隱藏內容,並去掉in類

      $.support.transition && this.$element.hasClass('collapse') ?
        this.$element.one($.support.transition.end, complete) :
        complete()
      }

果不其然,就是如此實現的。

此時hide方法執行完畢,下面執行jQuery原型上的最后一句代碼

if (typeof option == 'string') data[option]()//支持傳入方法名,執行該方法

如果你們還記得,這個data,依舊是與div3有關的實例化對象。再次執行原型上的hide方法,這是這個插件我認為蛋疼的一個地方,插件的API沒有很好的跟jQuery原型綁定上,僅僅依靠調用jQuery原型方法,實例化構造器去調用原型方法。導致jQuery隊形不能直接使用原型上的方法,作者這樣做的原因也有可能是防止自己在原型上定義的方法名和jQuery方法重名。遭到覆蓋。不過換個名字,可能就解決了么。。。

再執行一遍hide,就不演示了,ok整個actives.collapse('hide')執行完畢,繼續看show方法。

hasData || actives.data('collapse', null)//將data的collapse再次重新清空

將所有與actives有關的記憶全部刪除。

this.$element[dimension](0)//將高度清0,
this.transition('addClass', 'show', 'shown') this.$element[dimension](this.$element[0][scroll])//將當前點擊的標簽相關聯的內容的高度恢復,結果顯示效果

上面的代碼,先清空div1的高度,在通過transition方法加入in類,最后恢復div1的高度,蛋疼。。

上述主要描述了div3顯示,點擊div1的情景,如果我們要點擊div3,讓它自己隱藏,讓我們來看看代碼過程。

我們點擊div3,進入jQuery的collapse方法

/*
  * jQuery原型上自定義的方法
  * */
  $.fn.collapse = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('collapse')
        , options = typeof option == 'object' && option
      if (!data) $this.data('collapse', (data = new Collapse(this, options)))//實例化構造器
      if (typeof option == 'string') data[option]()//支持傳入方法名,執行該方法
    })
  }

進入構造器

/*
  * 構造器
  * */
  var Collapse = function ( element, options ) {
      this.$element = $(element)
    this.options = $.extend({}, $.fn.collapse.defaults, options)
    if (this.options["parent"]) {
      this.$parent = $(this.options["parent"])//獲取整個控件的jQuery對象
    }
    this.options.toggle && this.toggle()//實例化執行原型上的toggle方法
  }

好吧,進入toggle方法

toggle: function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()//實例化初次執行show方法
      }

此時對象本身擁有in類,所以執行hide方法,ok,搞定。

其實這個插件還有幾種情況,這里就不一一演示了。

沒有很好的綁定jQuery原型,導致調用方法,實例化兩次構造器,使得我們走代碼的流程比較多,有點耐心,應該沒問題。

內容不多,時間剛好,以上是我的一點讀碼體會,如有錯誤,請指出,大家共通學習。

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM