/** * b.tabs.js * base on Bootstrap Tab * * 导航功能扩展,可动态添加,可关闭 * 使用后可将系统改造为以标签页来打开页面的模式 * * @author Terry * created : 2016.03.17 * * changelog: * 2017.07.21 - 重构代码 * 解决IE下关闭标签页后切换其它标签页不能获得焦点问题 * 2017.08.03 - 增加内部高度修正功能 * 增加标签拖拽功能(依赖jquery-ui功能库,需要引入脚本) * 修复部分Bug */ !function ($) { "use strict"; var defaults = { /** * 载入标签页内容,登录超时后跳转的链接 */ 'loginUrl' : '/', /** * 自定义样式 */ 'className' : undefined, /** * 是否允许标签被拖拽排序,默认允许 * 拖拽功能依赖jquery-ui脚本库,请在使用之前引入功能库 * 设置“noSort”样式可以让标签不被排序 */ 'sortable' : true, /** * 浏览窗口尺寸发生变化时执行的回调 */ 'resize' : undefined }; /** * 常量 */ var constants = { closeBtnTemplate : '', //设置该样式的tab不会被关闭 noCloseClass : 'noclose', //设置该样式不会被拖拽修改位置 noSortClass : 'noSort', prefixKey : 'bTabs_' }; var bTabs = function(box,p){ this.$container = box; this.openTabs = new Array(); this.p = p; }; /** * 版本 */ bTabs.version = '1.0'; /** * 初始化 */ bTabs.prototype.init = function(){ var self = this,c = constants, $tabs = this.$container, openTabs = this.openTabs, p = this.p; $($tabs).addClass('bTabs'); if(p.className) $($tabs).addClass(p.className); $('ul.nav-tabs a',$($tabs)).each(function(i,row){ var li = $(this).closest('li'); if(li && !$(li).hasClass(c.noCloseClass)) $(row).append(c.closeBtnTemplate); }); $('div.tab-content div.tab-pane',$tabs).each(function(i,row){ openTabs.push($(this).attr('id')); }); //为关闭图标绑定事件,并适用于动态新增的 $('ul.nav-tabs',$tabs).on('click','button',function(e){ var id = $(this).parent().attr('href').replace('#', ''); self.closeTab(id); }); //处理窗口拖拽排序功能 if(p.sortable && $.fn.sortable){ $('ul.nav-tabs',$tabs).sortable({ items : "li:not(."+c.noSortClass+")", cancel : "li:not(.active)", axis : "x", placeholder : 'bTabsPlaceHolder', forcePlaceholderSize : true, stop : function(e,ui){} }).disableSelection(); } if(p && p.resize && $.isFunction(p.resize)){ p.resize(); self.innerResize(); $(window).off('resize.bTabs').on('resize.bTabs',function(e){ p.resize(); self.innerResize(); }); } }; /** * 内部高度调整 */ bTabs.prototype.innerResize = function(){ var $tabs = this.$container; //高度计算 var mainHeight = $($tabs).innerHeight(); var tabBarHeight = $('ul.nav-tabs',$tabs).outerHeight(true); $('div.tab-content',$tabs).height(mainHeight - tabBarHeight); }; /** * 新增一个tab,但如果是已存在的tab则只是激活它,而不再新增 * * @param id {string} 模块ID * @param title {string} 标题 * @param url {string} 目标链接地址 * @param loginCheck {function}可选参数,不传则直接使用iframe打开界面 */ bTabs.prototype.addTab = function(id,title,url,loginCheck){ if(!id || !title || !url) console.error('新增tab时,id,title,url参数为必须传递参数!'); var c = constants, $tabs = this.$container, openTabs = this.openTabs, p = this.p; var tabId = c.prefixKey + id; if(openTabs && $.isArray(openTabs) && openTabs.length>0){ var exist = false;//是否已存在 $.each(openTabs,function(i,row){ if(row == tabId){ exist = true; return false; } }); //若功能已存在,则直接切换 if(exist){ $('ul.nav-tabs a[href="#'+tabId+'"]',$tabs).tab('show'); return; } }else openTabs = new Array(); $('ul.nav-tabs',$tabs).append('
  • '+title+c.closeBtnTemplate+'
  • '); var content = $('
    '); $('div.tab-content',$tabs).append(content); //切换到新增加的tab上 $('ul.nav-tabs li:last a',$tabs).tab('show'); openTabs.push(tabId); var openIframe = function(){ $(content).append(''); }; //进行登录验证 if(loginCheck && $.isFunction(loginCheck)){ if(loginCheck()) openIframe(); else if(p && p.loginUrl) window.top.location.replace(p.loginUrl); }else openIframe(); }; /** * 关闭tab * @param id */ bTabs.prototype.closeTab = function(id,toId){ var c = constants, $tabs = this.$container, openTabs = this.openTabs; var thisTab = $('#' + id); //在移除标签页之前,先把iframe移除,解决在IE下,窗口上的输入控件获得不了焦点的问题 if($('iframe',$(thisTab)).size() > 0) $('iframe',$(thisTab)).remove(); //移除内容区 $(thisTab).remove(); var a = $('ul.nav-tabs a[href="#'+id+'"]',$tabs); var li = $(a).closest('li'); //获得当前tab的前一个tab var prevLi = $(li).prev(); //移除Tab li.remove(); if(openTabs && $.isArray(openTabs) && openTabs.length>0){ var index = -1; $.each(openTabs,function(i,d){ if(d == id){ index = i; return false; } }); if(index != -1) openTabs.splice(index,1); } //激活被关闭Tab邻的Tab,若没有则不处理 if(toId != "" && toId !=undefined) { toId = c.prefixKey + toId; $('ul.nav-tabs a[href="#' + toId + '"]', $tabs).tab('show'); $("#"+toId).find("iframe")[0].contentWindow.location.reload(); }else { if (prevLi.size() > 0) $('a', $(prevLi)).tab('show'); } }; /** * 插件初始化入口 */ function Plugin(p){ return this.each(function(){ //参数合并时允许读取在html元素上定义的'data-'系列的参数 var $this = $(this), data = $this.data('bTabs'), params = $.extend({}, defaults, $this.data(), typeof p == 'object' && p); if(!data) $this.data('bTabs', (data = new bTabs(this,params))); data.init(); }); } /** * 新增标签页 * @param id * @param title * @param url * @param loginCheck * @returns {*} */ function bTabsAdd(id,title,url,loginCheck){ return this.each(function(){ if(!id || !title || !url) return; var $this = $(this),data = $this.data('bTabs'); if(data) data.addTab(id,title,url,loginCheck); }); } /** * 关闭标签页 * @param id * @returns {*} */ function bTabsClose(id){ return this.each(function(){ if(!id || !title || !url) return; var $this = $(this),data = $this.data('bTabs'); if(data) data.closeTab(id); }); } /** * 关闭标签页,用于外部调用 * @param id * @returns {*} */ function CloseTabs(id,toId){ var c = constants; id = c.prefixKey+id; return this.each(function(){ if(!id) return; var $this = $(this),data = $this.data('bTabs'); if(data) data.closeTab(id,toId); }); } var old = $.fn.bTabs; $.fn.bTabs = Plugin; $.fn.bTabs.Constructor = bTabs; $.fn.bTabsAdd = bTabsAdd; $.fn.bTabsClose = bTabsClose; $.fn.CloseTabs = CloseTabs; // 处理新旧版本冲突 // ================= $.fn.bTabs.noConflict = function () { $.fn.bTabs = old; return this; }; }(window.jQuery);