b.tabs.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /**
  2. * b.tabs.js
  3. * base on Bootstrap Tab
  4. *
  5. * 导航功能扩展,可动态添加,可关闭
  6. * 使用后可将系统改造为以标签页来打开页面的模式
  7. *
  8. * @author Terry
  9. * created : 2016.03.17
  10. *
  11. * changelog:
  12. * 2017.07.21 - 重构代码
  13. * 解决IE下关闭标签页后切换其它标签页不能获得焦点问题
  14. * 2017.08.03 - 增加内部高度修正功能
  15. * 增加标签拖拽功能(依赖jquery-ui功能库,需要引入脚本)
  16. * 修复部分Bug
  17. */
  18. !function ($) {
  19. "use strict";
  20. var defaults = {
  21. /**
  22. * 载入标签页内容,登录超时后跳转的链接
  23. */
  24. 'loginUrl' : '/',
  25. /**
  26. * 自定义样式
  27. */
  28. 'className' : undefined,
  29. /**
  30. * 是否允许标签被拖拽排序,默认允许
  31. * 拖拽功能依赖jquery-ui脚本库,请在使用之前引入功能库
  32. * 设置“noSort”样式可以让标签不被排序
  33. */
  34. 'sortable' : true,
  35. /**
  36. * 浏览窗口尺寸发生变化时执行的回调
  37. */
  38. 'resize' : undefined
  39. };
  40. /**
  41. * 常量
  42. */
  43. var constants = {
  44. closeBtnTemplate : '<button type="button" class="navTabsCloseBtn" title="关闭" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>',
  45. //设置该样式的tab不会被关闭
  46. noCloseClass : 'noclose',
  47. //设置该样式不会被拖拽修改位置
  48. noSortClass : 'noSort',
  49. prefixKey : 'bTabs_'
  50. };
  51. var bTabs = function(box,p){
  52. this.$container = box;
  53. this.openTabs = new Array();
  54. this.p = p;
  55. };
  56. /**
  57. * 版本
  58. */
  59. bTabs.version = '1.0';
  60. /**
  61. * 初始化
  62. */
  63. bTabs.prototype.init = function(){
  64. var self = this,c = constants, $tabs = this.$container, openTabs = this.openTabs, p = this.p;
  65. $($tabs).addClass('bTabs');
  66. if(p.className) $($tabs).addClass(p.className);
  67. $('ul.nav-tabs a',$($tabs)).each(function(i,row){
  68. var li = $(this).closest('li');
  69. if(li && !$(li).hasClass(c.noCloseClass)) $(row).append(c.closeBtnTemplate);
  70. });
  71. $('div.tab-content div.tab-pane',$tabs).each(function(i,row){
  72. openTabs.push($(this).attr('id'));
  73. });
  74. //为关闭图标绑定事件,并适用于动态新增的
  75. $('ul.nav-tabs',$tabs).on('click','button',function(e){
  76. var id = $(this).parent().attr('href').replace('#', '');
  77. self.closeTab(id);
  78. });
  79. //处理窗口拖拽排序功能
  80. if(p.sortable && $.fn.sortable){
  81. $('ul.nav-tabs',$tabs).sortable({
  82. items : "li:not(."+c.noSortClass+")",
  83. cancel : "li:not(.active)",
  84. axis : "x",
  85. placeholder : 'bTabsPlaceHolder',
  86. forcePlaceholderSize : true,
  87. stop : function(e,ui){}
  88. }).disableSelection();
  89. }
  90. if(p && p.resize && $.isFunction(p.resize)){
  91. p.resize();
  92. self.innerResize();
  93. $(window).off('resize.bTabs').on('resize.bTabs',function(e){
  94. p.resize();
  95. self.innerResize();
  96. });
  97. }
  98. };
  99. /**
  100. * 内部高度调整
  101. */
  102. bTabs.prototype.innerResize = function(){
  103. var $tabs = this.$container;
  104. //高度计算
  105. var mainHeight = $($tabs).innerHeight();
  106. var tabBarHeight = $('ul.nav-tabs',$tabs).outerHeight(true);
  107. $('div.tab-content',$tabs).height(mainHeight - tabBarHeight);
  108. };
  109. /**
  110. * 新增一个tab,但如果是已存在的tab则只是激活它,而不再新增
  111. *
  112. * @param id {string} 模块ID
  113. * @param title {string} 标题
  114. * @param url {string} 目标链接地址
  115. * @param loginCheck {function}可选参数,不传则直接使用iframe打开界面
  116. */
  117. bTabs.prototype.addTab = function(id,title,url,loginCheck){
  118. if(!id || !title || !url) console.error('新增tab时,id,title,url参数为必须传递参数!');
  119. var c = constants, $tabs = this.$container, openTabs = this.openTabs, p = this.p;
  120. var tabId = c.prefixKey + id;
  121. if(openTabs && $.isArray(openTabs) && openTabs.length>0){
  122. var exist = false;//是否已存在
  123. $.each(openTabs,function(i,row){
  124. if(row == tabId){
  125. exist = true;
  126. return false;
  127. }
  128. });
  129. //若功能已存在,则直接切换
  130. if(exist){
  131. $('ul.nav-tabs a[href="#'+tabId+'"]',$tabs).tab('show');
  132. return;
  133. }
  134. }else openTabs = new Array();
  135. $('ul.nav-tabs',$tabs).append('<li><a href="#'+tabId+'" title="'+title+'" data-toggle="tab">'+title+c.closeBtnTemplate+'</a></li>');
  136. var content = $('<div class="tab-pane" id="'+tabId+'"></div>');
  137. $('div.tab-content',$tabs).append(content);
  138. //切换到新增加的tab上
  139. $('ul.nav-tabs li:last a',$tabs).tab('show');
  140. openTabs.push(tabId);
  141. var openIframe = function(){
  142. $(content).append('<iframe frameborder="0" scrolling="yes" style="width:100%;height:100%;min-width:1150px;border:0px;" src="'+url+'"></iframe>');
  143. };
  144. //进行登录验证
  145. if(loginCheck && $.isFunction(loginCheck)){
  146. if(loginCheck()) openIframe();
  147. else if(p && p.loginUrl) window.top.location.replace(p.loginUrl);
  148. }else openIframe();
  149. };
  150. /**
  151. * 关闭tab
  152. * @param id
  153. */
  154. bTabs.prototype.closeTab = function(id,toId){
  155. var c = constants, $tabs = this.$container, openTabs = this.openTabs;
  156. var thisTab = $('#' + id);
  157. //在移除标签页之前,先把iframe移除,解决在IE下,窗口上的输入控件获得不了焦点的问题
  158. if($('iframe',$(thisTab)).size() > 0) $('iframe',$(thisTab)).remove();
  159. //移除内容区
  160. $(thisTab).remove();
  161. var a = $('ul.nav-tabs a[href="#'+id+'"]',$tabs);
  162. var li = $(a).closest('li');
  163. //获得当前tab的前一个tab
  164. var prevLi = $(li).prev();
  165. //移除Tab
  166. li.remove();
  167. if(openTabs && $.isArray(openTabs) && openTabs.length>0){
  168. var index = -1;
  169. $.each(openTabs,function(i,d){
  170. if(d == id){
  171. index = i;
  172. return false;
  173. }
  174. });
  175. if(index != -1) openTabs.splice(index,1);
  176. }
  177. //激活被关闭Tab邻的Tab,若没有则不处理
  178. if(toId != "" && toId !=undefined) {
  179. toId = c.prefixKey + toId;
  180. $('ul.nav-tabs a[href="#' + toId + '"]', $tabs).tab('show');
  181. $("#"+toId).find("iframe")[0].contentWindow.location.reload();
  182. }else {
  183. if (prevLi.size() > 0) $('a', $(prevLi)).tab('show');
  184. }
  185. };
  186. /**
  187. * 插件初始化入口
  188. */
  189. function Plugin(p){
  190. return this.each(function(){
  191. //参数合并时允许读取在html元素上定义的'data-'系列的参数
  192. var $this = $(this),
  193. data = $this.data('bTabs'),
  194. params = $.extend({}, defaults, $this.data(), typeof p == 'object' && p);
  195. if(!data) $this.data('bTabs', (data = new bTabs(this,params)));
  196. data.init();
  197. });
  198. }
  199. /**
  200. * 新增标签页
  201. * @param id
  202. * @param title
  203. * @param url
  204. * @param loginCheck
  205. * @returns {*}
  206. */
  207. function bTabsAdd(id,title,url,loginCheck){
  208. return this.each(function(){
  209. if(!id || !title || !url) return;
  210. var $this = $(this),data = $this.data('bTabs');
  211. if(data) data.addTab(id,title,url,loginCheck);
  212. });
  213. }
  214. /**
  215. * 关闭标签页
  216. * @param id
  217. * @returns {*}
  218. */
  219. function bTabsClose(id){
  220. return this.each(function(){
  221. if(!id || !title || !url) return;
  222. var $this = $(this),data = $this.data('bTabs');
  223. if(data) data.closeTab(id);
  224. });
  225. }
  226. /**
  227. * 关闭标签页,用于外部调用
  228. * @param id
  229. * @returns {*}
  230. */
  231. function CloseTabs(id,toId){
  232. var c = constants;
  233. id = c.prefixKey+id;
  234. return this.each(function(){
  235. if(!id) return;
  236. var $this = $(this),data = $this.data('bTabs');
  237. if(data) data.closeTab(id,toId);
  238. });
  239. }
  240. var old = $.fn.bTabs;
  241. $.fn.bTabs = Plugin;
  242. $.fn.bTabs.Constructor = bTabs;
  243. $.fn.bTabsAdd = bTabsAdd;
  244. $.fn.bTabsClose = bTabsClose;
  245. $.fn.CloseTabs = CloseTabs;
  246. // 处理新旧版本冲突
  247. // =================
  248. $.fn.bTabs.noConflict = function () {
  249. $.fn.bTabs = old;
  250. return this;
  251. };
  252. }(window.jQuery);