前言:
阅读建议:去github下载一个完整dom然后把,本篇代码复制进去然后运行就好了以地址
tab组件是非常简单的一种组件,因为这是一个系列,所以就顺便看了,其实它写的这个还算不错的,很有条例,也算是插件的规范写法,研究一下也不错
/* ======================================================================== * 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 Tab.prototype.show = function () { var $this = this.element//把a标签赋值给$this var $ul = $this.closest('ul:not(.dropdown-menu)')//closest 仅供插件开发者使用的方法,jquery1.7后就不建议使用了 冲a标签处向上寻找ul包裹元素 var selector = $this.data('target')//取出target if (!selector) {//没有target的话, selector = $this.attr('href')//把当前触发的a标签的某点,付给他 selector = selector && selector.replace(/.*(?=#[^s]*$)/, '') // strip for ie7 } if ($this.parent('li').hasClass('active')) return//发现已经时active了,则返回,没有泽继续向下执行 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] }) $previous.trigger(hideEvent) $this.trigger(showEvent) if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return var $target = $(selector) 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')//得到先前li.active var transition = callback && $.support.transition && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) function next() { $active .removeClass('active')//把原来的active去除 .find('> .dropdown-menu > .active') .removeClass('active')//在把menu下拉菜单下的active去掉 .end()//退到上一层 .find('[data-toggle="tab"]')//寻找他下面的a标签, .attr('aria-expanded', false)//aria-expanded 属性赋值为false element .addClass('active')//给当前触发的li负上active .find('[data-toggle="tab"]')//找到地下a标签 .attr('aria-expanded', true)//赋值为true if (transition) {//有毁掉函数的时候 element[0].offsetWidth // reflow for transition element.addClass('in') } else { element.removeClass('fade') } if (element.parent('.dropdown-menu').length) {//父元素时.dropdown-menu时执行 element .closest('li.dropdown') .addClass('active') .end() .find('[data-toggle="tab"]') .attr('aria-expanded', true) } callback && callback() } $active.length && transition ? $active .one('bsTransitionEnd', next) .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 自动给你初始化了,这样就可以不用写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);