bootstrap之tab.js分析

我一定要征服移動端佈局,深入分析bootstrap就成爲了捷徑之一。路雖長,我雖笨,但架不住傻逼似得堅持。加油!!

tabjs是bootstrap選項卡動態,裏面常見的下拉框等效果,今天來試試源碼難度,順帶溫習jQuery的API,何樂不爲,反正目前我都是小項目,jQuery,zepto,挺好!

插件外殼,立即執行函數,傳形參$和實參jQuery

+function ($) {}(jQuery);

偷個懶,直接放詳細註釋的源碼,由於能力不夠,可能會有些錯誤,歡迎指正


/* ========================================================================
 * Bootstrap: tab.js v3.3.7
 * http://getbootstrap.com/javascript/#tabs
 * ========================================================================
 * Copyright 2011-2016 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TAB CLASS DEFINITION
  // ====================

  var Tab = function (element) {
    // jscs:disable requireDollarBeforejQueryAssignment
    this.element = $(element)
    // jscs:enable requireDollarBeforejQueryAssignment
  }

  Tab.VERSION = '3.3.7'

  Tab.TRANSITION_DURATION = 150 //過渡時間css3的transition
  //tab原型show函數
  Tab.prototype.show = function () {
    var $this    = this.element
    var $ul      = $this.closest('ul:not(.dropdown-menu)') //closest() 方法獲得匹配選擇器的第一個祖先元素,從當前元素開始沿 DOM 樹向上。
    var selector = $this.data('target') //data() 方法向被選元素附加數據,或者從被選元素獲取數據。

    if (!selector) {//如果selector沒有數據
      selector = $this.attr('href') //attr() 方法設置或返回被選元素的屬性值,返回href地址
      //正則替換部分:任意個.不對#號記錄,以任意非空白字符結束。使用空字符串替換.#號前面字符
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }
    //如果當前li已經觸發,返回
    if ($this.parent('li').hasClass('active')) return

    var $previous = $ul.find('.active:last a') //選擇最後active的後代元素 a
    //jQuery.Event 構造器暴露出來,然後通過$.trigger來觸發hide.bs.tab事件
    var hideEvent = $.Event('hide.bs.tab', {
      relatedTarget: $this[0]
    })
    var showEvent = $.Event('show.bs.tab', {
      relatedTarget: $previous[0]
    })
    //trigger在每一個匹配的元素上觸發hideEvent自定義事件
    $previous.trigger(hideEvent)
    $this.trigger(showEvent)
    //isDefaultPrevented()根據事件對象中是否調用過 event.preventDefault() 方法來返回一個布爾值。
    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return

    var $target = $(selector)
    //傳參進入原型activate函數,實現隱藏顯示效果
    this.activate($this.closest('li'), $ul)
    this.activate($target, $target.parent(), function () {
      $previous.trigger({
        type: 'hidden.bs.tab',
        relatedTarget: $this[0]
      })
      $this.trigger({
        type: 'shown.bs.tab',
        relatedTarget: $previous[0]
      })
    })
  }

  Tab.prototype.activate = function (element, container, callback) {
    var $active    = container.find('> .active')//container後代active元素
    var transition = callback 
      && $.support.transition //jQuery.support 屬性包含表示不同瀏覽器特性或漏洞的屬性集。
      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
      //下一個
    function next() {
      $active
        .removeClass('active') //移除active類
        .find('> .dropdown-menu > .active') //選擇後代dropdown-menu的後代active元素
          .removeClass('active')//移除active類
        .end()//主要是在利用 jQuery 的鏈條屬性(命令鏈)通過 end(),我們可以把所有方法調用串聯在一起 恢復選擇上一級元素
        .find('[data-toggle="tab"]') //在.find('> .dropdown-menu > .active')上找到data-toggle="tab"屬性的元素
          .attr('aria-expanded', false) //無障礙閱讀設置爲false

      element
        .addClass('active') //在傳入元素上增加active類
        .find('[data-toggle="tab"]') //選擇data-toggle="tab"屬性的元素
          .attr('aria-expanded', true) //設置無障礙閱讀爲true
      //如果transition存在
      if (transition) {
        element[0].offsetWidth // reflow for transition
        element.addClass('in') //增加in類
      } else {
        element.removeClass('fade') //移除fade類
      }
      //若傳入元素的父級dropdown-menu存在
      if (element.parent('.dropdown-menu').length) {
        element
          .closest('li.dropdown') //closest() 方法獲得匹配選擇器的第一個祖先元素,從當前元素開始沿 DOM 樹向上。
            .addClass('active') //增加active類
          .end()//主要是在利用 jQuery 的鏈條屬性(命令鏈)通過 end(),我們可以把所有方法調用串聯在一起 恢復選擇上一級元素
          .find('[data-toggle="tab"]') //選擇data-toggle="tab"屬性元素
            .attr('aria-expanded', true)//無障礙閱讀屬性 true
      }

      callback && callback() //若callback爲true,則把callback當做函數執行;類似於if(callback){callback()}
    }
    //若 $active和transition都爲true,則執行$active
    $active.length && transition ?
      $active
        .one('bsTransitionEnd', next) //將next()綁定到bsTransitionEnd事件上
        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
      next()

    $active.removeClass('in')
  }


  // TAB PLUGIN DEFINITION
  // =====================

  function Plugin(option) {
    return this.each(function () {//加each是jquery插件的標配,意爲選中多個dom時挨個處理
      var $this = $(this)
      var data  = $this.data('bs.tab')//先取一下bs.tab   這一步是爲了緩存Tab對象的,這是必須的,不可能點擊一下tab就new Tab(this),

      if (!data) $this.data('bs.tab', (data = new Tab(this)))//如果沒有data,那麼將點擊的a標籤傳入tab,然後把Tab對象賦值給data
      if (typeof option == 'string') data[option]()//如果傳入的是字符串,則執行相應的方法
    })
  }


  var old = $.fn.tab

  $.fn.tab             = Plugin
  $.fn.tab.Constructor = Tab


  // TAB NO CONFLICT
  // ===============
  //防衝突代碼,爲了規範,應該加上
  $.fn.tab.noConflict = function () {
    $.fn.tab = old
    return this
  }


  // TAB DATA-API
  // ============
  // TAB DATA-API   自動給你初始化了,這樣就可以不用寫js代碼了
  var clickHandler = function (e) {
    e.preventDefault()//阻止事件冒泡
    Plugin.call($(this), 'show')
  }

  $(document)
    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)//pill這個是給膠囊導航用的,其實tab和pill原理都一樣,只是名字不一樣而已

}(jQuery);

每天努力一點,距離大神就近一點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章