先看bootstrap-tab.js的結構
var Tab = function ( element ) {} //構造器 Tab.prototype ={} //構造器的原型 $.fn.tab = function ( option ){} //jQuery原型上自定義的方法 $.fn.tab.Constructor = Tab //重寫jQuery原型上的自定義方法的構造器名 $(function () {}) //初始化
HTML結構
<ul class="nav nav-tabs"> <li class="active"><a href="#home" data-toggle="tab" >首頁</a></li> <li><a href="#profile" data-toggle="tab">介紹</a></li> <li><a href="#messages" data-toggle="tab">消息</a></li> <li><a href="#settings" data-toggle="tab">設置</a></li> </ul> <div class="tab-content"> <div class="tab-pane active" id="home">1</div> <div class="tab-pane" id="profile">2</div> <div class="tab-pane" id="messages">3</div> <div class="tab-pane" id="settings">4</div> </div>
先從初始化開始
/* * 初始化 * 給擁有data-toggle='tab'屬性的標簽綁定click事件 * */ $(function () { $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { e.preventDefault() $(this).tab('show')//向jQuery原型方法tab傳入參數show,應該執行show方法。this為擁有data-toggle屬性的a標簽對象 }) })
讓body監聽a標簽的click事件,並且阻止其冒泡,調用了jQuery的原型方法tab。
/* * jQuery原型上自定義的方法 * */ $.fn.tab = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('tab') if (!data) $this.data('tab', (data = new Tab(this)))//實例化構造器 if (typeof option == 'string') data[option]()//執行option的方法 }) }
這個結構跟之前的幾個插件差不多,不過最后它是執行了show方法的,進入構造器
var Tab = function ( element ) { this.element = $(element) }
將對象封裝成構造器實例的一個屬性。接下來我們執行show方法
show: function () { var $this = this.element , $ul = $this.closest('ul:not(.dropdown-menu)')//找到最近的不是dropdown類的ul元素 , selector = $this.attr('data-target') , previous , $target //獲取與a標簽對應的內容id if (!selector) { selector = $this.attr('href') selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } //如果一直點擊自己,這句之后的代碼將不執行 if ( $this.parent('li').hasClass('active') ) return previous = $ul.find('.active a').last()[0]//獲得擁有active類的原生a標簽對象,即上一次高亮的節點 $this.trigger({ type: 'show' , relatedTarget: previous }) $target = $(selector)//獲得內容節點的jQueryDOM對象 this.activate($this.parent('li'), $ul)//tab頁切換 this.activate($target, $target.parent(), function () { $this.trigger({ type: 'shown' , relatedTarget: previous }) })
根據標簽a的data-target屬性或是其href找到對應的id的dom節點。最后我們執行了兩次activate方法,其實大概猜的出來,一個方法控制a標簽的高亮顯示,另一個控制dom節點的顯示與隱藏
/* * 控制顯示與隱藏 * 參數主要形式是這樣的,一個是可以擁有active類的元素,另一個是其父類。 * 先找到父類下來所有擁有active類的節點,刪除它們的active,並將當前節點,也就是第一個參數加上active類。 * * */ , activate: function ( element, container, callback) { var $active = container.find('> .active') , transition = callback && $.support.transition//需要引入其他js文件,這里沒有引入。 && $active.hasClass('fade') console.log($active[0]) function next() { $active .removeClass('active') .find('> .dropdown-menu > .active') .removeClass('active') element.addClass('active') if (transition) { element[0].offsetWidth // reflow for transition element.addClass('in') } else { element.removeClass('fade') } if ( element.parent('.dropdown-menu') ) { element.closest('li.dropdown').addClass('active') } callback && callback() } transition ? $active.one($.support.transition.end, next) : next() $active.removeClass('in') }
邏輯比較簡單,一般遇到一個顯示其他同類不顯示的情況,基本都是這一套方法,增刪class來達到要求。但對於jQuery操作css完成class切換與javascript原生方法相比,哪個效率會更好一點呢?也希望有經驗的園友給予解答。
另外是部分css,表現了兩塊active類的作用
/*tab頁切換時的active作用*/ .nav-tabs > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus { color: #555555; cursor: default; background-color: #ffffff; border: 1px solid #ddd; border-bottom-color: transparent;//將底部邊框變透明 } /*dom*/ .tab-content > .tab-pane, .pill-content > .pill-pane { display: none; //原來為隱藏 } .tab-content > .active, .pill-content > .active { display: block; //加入active ,變為顯示 }
文實例為大家介紹實現tab選項卡的應用,此插件相對比較簡單,具體內容如下
源碼文件:
tab.js
實現原理:
1、單擊一個元素時,首先將原來高亮的元素取消
2、然后給被單擊元素進行高亮
3、如果單擊元素是下拉框中某個選項,則選中本身,還要選中下拉框
5、如果定義了動畫,先執行動畫,然后回調
源碼分析:
1、Show方法,是在單擊一個元素的時候觸發,會觸發如下四個事件
1.1、Hiden.bs.tab:隱藏上一個元素
1.2、Show.bs.tab:顯示當前元素
1.3、Hideen.bs.tab:隱藏上一個元素完成
1.4、Shown.bs.tab:顯示當前元素完成
1.5、Hiden/show事件源碼:
1
2
3
4
5
6
7
|
var
$previous = $ul.find(
'.active:last a'
)
var
hideEvent = $.Event(
'hide.bs.tab'
, {
relatedTarget: $
this
[0]
})
var
showEvent = $.Event(
'show.bs.tab'
, {
relatedTarget: $previous[0]
})
|
2、Active:激活當前對象
2.1、對導航元素增加aria-expanded屬性,標記此元素是否處於展開狀態
2.2、利用reflow機制,用獲取offsetWidth屬性來實現部分重繪