bootstrap插件學習-bootstrap.modal.js


先從bootstrap.modal.js的結構看起。

function($){
        var Modal = function(){}  //構造器
        Modal.prototype = function(){} //構造器的原型
        function ..(){}  //自定義方法 
        $.fn.modal = function(){} //在jQuery對象上自定方法
        $.fn.modal.defaults = {} //設置默認屬性
        $.fn.modal.Constructor = Modal //重置構造器名
        $(function(){})   //初始化
    }(window.jQuery)

其HTML結構

<a class="btn" data-toggle="modal" href="#myModal" >點擊觸發對話框</a>

<div class="modal" id="myModal">
      <div class="modal-header">
        <a class="close" data-dismiss="modal">×</a>
        <h3>對話框標題</h3>
      </div>
      <div class="modal-body">
        <p>對話框內容</p>
      </div>
      <div class="modal-footer">
      <a href="#" class="btn" data-dismiss="modal">關閉</a>
      <a href="#" class="btn btn-primary" data-dismiss="modal">保存更新</a>
  </div>
</div>

我們開始過一遍插件源碼:從初始化開始

$(function () {
     /*
     * 在所有有data-toggle='modal'屬性的標簽上幫上click事件,一般為a標簽
     * /.*(?=#[^\s]+$)/表示如果匹配成功將#之前的信息刪除
     * 對於jQuery對象,比如a標簽有data-xx類型的,在其data方法中都可以顯示
     * 將a標簽data-target指向的或是href的錨點指向的元素傳入modal方法里
     * */
    $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
      var $this = $(this), href
        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
        , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data());
      e.preventDefault()
      $target.modal(option)
    })
  })

根據HTML提供的結構,$target為a標簽所指向的彈出框div的Jquery對象。另外$this.data()存在數據,為{toggle:'modal'},這個我在注釋中已經解釋。最后執行$target.modal(option),我們進入jQuery對象的這個方法。

$.fn.modal = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('modal')
        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
      if (!data) $this.data('modal', (data = new Modal(this, options)))//為modal綁定對象
      if (typeof option == 'string') data[option]()
      else if (options.show) data.show()
    })
  }

初始化一些參數,在彈出框div上加入了一個modal屬性,如果這個modal屬性不存在,則實例化Modal構造器。最后執行show方法,因為此時你已經點擊了a標簽,讓div顯示。代碼中有if(typeof option == 'string')data[option],表示代碼支持傳入方法名,執行該方法,在執行show方法之前,我們先進入Modal的構造器中看看。

/*
  * 構造器,為所有data-dismiss='modal'屬性的標簽綁定原型上的hide方法
  * */
  var Modal = function ( content, options ) {
    this.options = options
    this.$element = $(content)
      .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
  }

很簡單,讓帶有data-dismiss='modal'屬性的標簽的click事件交給彈出框div代理,注意這里的執行的方法。這里為什么要$.proxy(this.hide,this)這樣寫,第一,需要明白此時的this表示着構造器的實例,代理的事件需要使用到實例的hide方法,為什么實例擁有hide方法,很簡單this是Modal的實例,它繼承了Modal原型的方法。那proxy方法中的第二個this,則表示着這個hide方法的調用者,即上下文,可以試想一下,如果我們不修改這個,那執行這個方法時,其里面的this是不是指向了調用它的a標簽呢?(注意留意HTML結構,擁有data-dismiss屬性的三個a標簽,其實分別就是彈出框的關閉按鈕等),那原來定義在原型上的hide方法中的this的屬性將不能在正常使用。
綜上,實例化,主要就是給彈出框綁定了hide事件,為將來關閉彈出框,做准備。

好,回到之前JQuery的modal方法上,最后我們執行了show方法,進入show方法。

 下面是執行的流程圖,就是各個方法的執行順序

show -> escape -> backdrop
hide ->escape -> hideModal -> backdrop

show

    , show: function () {
        var that = this

        if (this.isShown) return

        $('body').addClass('modal-open')//給body加上modal-open類

        this.isShown = true//將isShown屬性設置成true

        this.$element.trigger('show');//沒理解
escape.call(
this)//加上鍵盤事件 backdrop.call(this, function () { var transition = $.support.transition && that.$element.hasClass('fade') //console.log(that.$element); /* * 插入彈出層 * */ !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position that.$element .show()//jQuery方法顯示 if (transition) { that.$element[0].offsetWidth // force reflow } that.$element.addClass('in') transition ? that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : that.$element.trigger('shown') }) }

談到show和hide的時候,我們需要留意它們源碼中的一些我們認為的'廢'操作,其實它能幫助我們實現擴展。比如給body加modal-open這個類,如果你要在打開彈出層,執行其他程序,可以通過判斷這個類來實現,這是bootstrap它自身已經提供的標識。escape()方法是一個添加鍵盤事件和刪除鍵盤事件的方法,它可以讓你按enter鍵也能關閉彈出框,比較簡單。

接下來我們進入backdrop方法

/*
  * 生成遮罩層,並且控制遮罩層的顯示或刪除
  * */
  function backdrop( callback ) {
          var that = this
      , animate = this.$element.hasClass('fade') ? 'fade' : ''

    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate
      //console.log(doAnimate);
      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
        .appendTo(document.body)//遮罩層,讓彈出框顯示時,背景被遮罩,此時為透明的

      if (this.options.backdrop != 'static') {
        this.$backdrop.click($.proxy(this.hide, this))
      }

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')//加入in類,顯示遮罩層

      doAnimate ?
        this.$backdrop.one($.support.transition.end, callback) :
        callback()
      //打開時,執行callback()回調
    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')//刪除in,遮罩層透明
      $.support.transition && this.$element.hasClass('fade')?
        this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
        removeBackdrop.call(this)
        //一般執行removeBackdrop()函數
    } else if (callback) {
      callback()
    }
  }

這里為什么要判斷彈出框是否有fade類,在bootstrap.css中,.fade擁有left:-25%的屬性,當.fade .in時則left變為10%,在版本較高的瀏覽器中,有自上向下的移動的效果(低版本瀏覽器沒有效果,不過這個可以jQuery實現...),這個部分需要我們結合css樣式看,注意in的樣式,就可以了,彈出框顯示的最后一步,執行callback回調,顯示彈出框,並給彈出框加上in類,80%透明度。最后完成顯示。

之前因為我們已經在彈出框的三個a標簽上都綁定了hide事件,所以當我們點擊關閉時,執行hide方法

hide: function ( e ) {
        e && e.preventDefault()

        if (!this.isShown) return

        var that = this
        this.isShown = false

        $('body').removeClass('modal-open')

        escape.call(this)//關閉按鍵事件

        this.$element
          .trigger('hide')
          .removeClass('in')//jQuery方法,將彈出框隱藏,並將div的class去in

        $.support.transition && this.$element.hasClass('fade') ?
          hideWithTransition.call(this) :
          hideModal.call(this)
      }

其實跟show方法差不多,主要是給show擦屁股,進入hideModal方法

function hideModal( that ) {
    this.$element
      .hide() //刪除效果更好
      .trigger('hidden')

    backdrop.call(this)
  }

蠻蛋疼的方法,還是調用backdrop。最后刪除時我們調用的是removeBackdrop方法。

/*
  * 清除遮罩層
  * */
  function removeBackdrop() {
    this.$backdrop.remove()
    this.$backdrop = null
  }

將之前創建的遮罩層刪除。以上完成一遍彈出框的打開顯示。

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

 

 

 

 

 


免責聲明!

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



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