先看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 ,變為顯示
}
內容不多,時間剛好,以上是我的一點讀碼體會,如有錯誤,請指出,大家共通學習。