content-tabs.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /**
  2. * UI v1.1.0
  3. * Copyright 2017-2018 Muyao
  4. * Licensed under the Muyao License 1.0
  5. */
  6. (function (window, document, $) {
  7. 'use strict';
  8. $.site.contentTabs = {
  9. $instance: $('#admui-navTabs .site-menu'),
  10. $content: $('#admui-pageContent'),
  11. storageKey: 'admui.base.contentTabs',
  12. tabId: 0,
  13. relative: 0,
  14. tabTimeout: 30,
  15. init: function () {
  16. this.bind();
  17. this._defaultTab();
  18. },
  19. bind: function () {
  20. var self = this,
  21. $navContabs = $("#admui-siteConTabs"),
  22. $navContent = $navContabs.find("ul.con-tabs");
  23. this.tabWidth = $navContent.find("li").width();
  24. this.view = $navContabs.find(".contabs-scroll").width();
  25. this.ifameTabs();
  26. // 标签页的左右移动 && 关闭单个标签页 && 切换标签页
  27. $navContabs
  28. .on('click.site.contabs', 'button.pull-left', function () {
  29. self.tabPosition($navContent, self.tabWidth, "right");
  30. })
  31. .on('click.site.contabs', '.pull-right>.btn-icon', function () {
  32. var content = $navContent.width();
  33. self.tabPosition($navContent, self.tabWidth, "left", self.view, content);
  34. })
  35. .on('click.site.contabs', 'ul.con-tabs>li', function (e) {
  36. var $target = $(e.target), $item = $(this);
  37. if ($target.is("i.wb-close-mini")) { // 关闭
  38. self.closeTab($item);
  39. } else if (!$item.is(".active")) { // 切换
  40. $item.siblings("li").removeClass("active");
  41. $item.addClass("active");
  42. self._checkoutTab($item.find('a'));
  43. self.enable($item);
  44. }
  45. e.preventDefault();
  46. });
  47. // 刷新当前页 && 关闭其他 && 所有标签页
  48. $navContabs
  49. .on('click.site.contabs', '.pull-right li.reload-page', function () {
  50. var $navLi = $navContabs.find('ul.con-tabs>li.active>a'),
  51. tabUrl = $navLi.attr('href');
  52. // 刷新当前页
  53. self.$content.children('[src="' + tabUrl + '"]').attr('src', tabUrl);
  54. })
  55. .on('click.site.contabs', '.pull-right li.close-other', function () {
  56. var $navLis = $navContabs.find('ul.con-tabs>li');
  57. $navLis.each(function () {
  58. var $that = $(this), tabId;
  59. if (!$that.is('.active') && $that.index() !== 0) {
  60. tabId = $that.find('a').attr('target');
  61. $that.remove();
  62. self.$content.children('[name="' + tabId + '"]').remove();
  63. self._updateSetting(tabId);
  64. }
  65. });
  66. $navContent.animate({left: 0}, 100);
  67. self.btnView('hide');
  68. })
  69. .on('click.site.contabs', '.pull-right li.close-all', function () {
  70. var $tabs = $navContabs.find('ul.con-tabs>li'),
  71. $checked = $tabs.eq(0);
  72. $tabs.each(function () {
  73. var $that = $(this), tabId;
  74. if ($that.index() !== 0) {
  75. tabId = $that.find('a').attr('target');
  76. $that.remove();
  77. self._updateSetting(tabId);
  78. }
  79. });
  80. $navContent.animate({left: 0}, 100);
  81. self.btnView('hide');
  82. $checked.addClass('active');
  83. self.enable($tabs.eq(0));
  84. self._checkoutTab($checked.find('a'));
  85. // 关闭所有
  86. self.$content.children(':not(:first)').remove();
  87. self.tabSize();
  88. });
  89. // 登出清楚标签页缓存
  90. $(document).on('click', '#admui-signOut', function () {
  91. $.sessionStorage.remove(self.storageKey);
  92. });
  93. // 浏览器窗口大小改变,标签页的对应状态
  94. $(window).on('resize', this.resize);
  95. },
  96. ifameTabs: function (el) { // 为当前doc对象中的a[data-iframe]标签绑定创建标签页功能
  97. var self = this,
  98. doc = el === undefined ? document : el;
  99. // 新建标签页
  100. $(doc).on('click', 'a[data-iframe]', function (e) {
  101. var $item = $(this), urlResult,
  102. url = $item.attr('href'),
  103. title = $.trim($item.text()) || $.trim($item.attr('title')),
  104. iframeContent = $item.data('iframe') || '#admui-pageContent',
  105. tabResult = $item.is('[target="_blank"]');
  106. urlResult = new RegExp(/^([a-zA-z]+:|#|javascript|www\.)/); // 不执行新建标签页操作的地址
  107. if (urlResult.test(url)) {
  108. return;
  109. }
  110. if (tabResult && iframeContent === '#admui-pageContent') {
  111. window.history.replaceState(null, '', '#!' + url);
  112. self.tabType = true;
  113. self.buildTab({name: title, url: url});
  114. if (!self.$instance.find($item).length) {
  115. self.enable($item.parent());
  116. }
  117. } else if (!tabResult) {
  118. $(iframeContent).find('iframe.active').attr('src', url);
  119. }
  120. e.preventDefault();
  121. });
  122. },
  123. _checkoutTab: function (tab) { // 标签页的切换
  124. var $content = this.$content,
  125. tabId = tab.attr('target'),
  126. tabTitle = $.trim(tab.attr('title')),
  127. tabUrl = tab.attr('href'),
  128. $checkedTab = $content.children('iframe[name="' + tabId + '"]');
  129. $('title').text(tabTitle);
  130. if (!this.tabType) {
  131. window.history.replaceState(null, '', '#!' + tabUrl);
  132. }
  133. if (!$checkedTab.attr('src')) {
  134. $checkedTab.attr('src', tabUrl);
  135. }
  136. $content.children('.active').removeClass('active');
  137. $checkedTab.addClass('active');
  138. $.site.iframeEvents($checkedTab);
  139. this._updateSetting('checked', tabId);
  140. this.tabType = false;
  141. },
  142. _defaultTab: function () { // 存储默认标签的信息
  143. var $defaultTab = $('#admui-siteConTabs').find('li:first > a'), settings;
  144. settings = this.settings = $.sessionStorage.get(this.storageKey);
  145. if (settings === null) {
  146. settings = $.extend(true, {}, {
  147. 'iframe-0': {
  148. 'url': $defaultTab.attr('href'),
  149. 'name': $defaultTab.text()
  150. },
  151. 'checked': $defaultTab.attr('target'),
  152. 'tabId': this.tabId
  153. });
  154. this._updateSetting(settings);
  155. } else {
  156. this.tabId = settings.tabId;
  157. }
  158. },
  159. _updateSetting: function (item, value) {
  160. var settings = $.sessionStorage.get(this.storageKey);
  161. settings = settings ? settings : {};
  162. if (typeof item === 'object') {
  163. $.extend(true, settings, item);
  164. } else if (!value) {
  165. delete settings[item];
  166. } else {
  167. settings[item] = value;
  168. }
  169. $.sessionStorage.set(this.storageKey, settings, this.tabTimeout);
  170. },
  171. resize: function () {
  172. var self = $.site.contentTabs,
  173. $navContabs = $(".site-contabs"),
  174. $navContent = $navContabs.find("ul.con-tabs");
  175. self._throttle(function () {
  176. self.view = $navContabs.find(".contabs-scroll").width();
  177. self.tabEvent($navContent, 'media');
  178. }, 200)();
  179. },
  180. enable: function ($el) { // 左侧菜单定位
  181. var $instance = this.$instance,
  182. href = $.trim($el.find('a').attr('href')),
  183. _result = href.indexOf('#'),
  184. tabUrl = _result > 0 ? href.substring(0, _result) : href,
  185. $current = $instance.find('a[href="' + tabUrl + '"]'),
  186. $currentParents, $currentLi, $currentHasSub, $instanceLi, checkedId, currentId;
  187. if ($current.length === 0) {
  188. $.site.menu.refresh();
  189. return;
  190. }
  191. checkedId = $.trim($instance.closest('div.tab-pane.active').attr('id'));
  192. currentId = $.trim($current.closest('div.tab-pane').attr('id'));
  193. if (checkedId !== currentId) {
  194. $('#admui-navbar a[href="#' + currentId + '"]').tab('show');
  195. }
  196. $currentLi = $current.closest('li').siblings('li.open');
  197. $currentParents = $current.parents('li.has-sub');
  198. $currentHasSub = $current.closest('li.has-sub').siblings('li.open');
  199. $instanceLi = $instance.find('li.open');
  200. $instance.find('li.active').trigger('deactive.site.menu');
  201. $current.closest('li').trigger('active.site.menu');
  202. if ($currentLi.length) {
  203. $currentLi.trigger('close.site.menu');
  204. }
  205. if (!$current.closest('li.has-sub').hasClass('open')) {
  206. if ($currentHasSub.length) {
  207. $currentHasSub.trigger('close.site.menu');
  208. }
  209. if ($instanceLi.length) {
  210. $instanceLi.not($currentParents).trigger('close.site.menu');
  211. }
  212. $currentParents.trigger('open.site.menu');
  213. }
  214. },
  215. buildTab: function (opt) { // 新建标签页
  216. var $tabNav = $(".con-tabs"), tabName, obj = {}, tabId,
  217. _url = opt.url,
  218. _result = _url.indexOf('#'),
  219. tabUrl = _result > 0 ? _url.substring(0, _result) : _url;
  220. if (this._checkTabs($tabNav, tabUrl)) { // 标签查重
  221. return;
  222. }
  223. tabId = ++this.tabId;
  224. tabName = 'iframe-' + tabId;
  225. // 修改当前选中的标签页
  226. $tabNav.find("li.active").removeClass("active");
  227. $tabNav.append('<li class="active"><a href="' + tabUrl + '" target="' + tabName +
  228. '" title="' + opt.name + '' + '" rel="contents"><span>' + opt.name + '</span><i class="icon' +
  229. ' wb-close-mini">' + '</i></a></li>');
  230. obj[tabName] = {
  231. 'url': tabUrl,
  232. 'name': opt.name
  233. };
  234. $.extend(obj, {
  235. 'checked': tabName,
  236. 'tabId': tabId
  237. });
  238. this._updateSetting(obj);
  239. // 修改页面标题
  240. opt.name = opt.name === '' ? '无标题' : opt.name;
  241. $('title').text($.trim(opt.name));
  242. this.buildIframe(_url);
  243. this.tabSize();
  244. this.tabEvent($tabNav, 'media');
  245. this.tabType = false;
  246. },
  247. _checkTabs: function (doc, url) { // 标签查重
  248. var x, prevAll, nextAll, contentW,
  249. _view = this.view, _tab = this.tabWidth,
  250. $currenttab = doc.find("a[href='" + url + "']").closest('li');
  251. if ($currenttab.hasClass('active')) { // 标签存在&已选中
  252. return true;
  253. }
  254. if ($currenttab.size() <= 0) { // 标签不存在
  255. return false;
  256. }
  257. // 标签存在未选中
  258. doc.find("li.active").removeClass("active");
  259. $currenttab.addClass("active");
  260. // 切换标签页
  261. this._checkoutTab($currenttab.find('a'));
  262. // 标签位移到可视界面显示
  263. x = doc.position().left;
  264. contentW = doc.width();
  265. prevAll = $currenttab.prevAll('li').size() * _tab;
  266. nextAll = $currenttab.nextAll('li').size() * _tab;
  267. if (-prevAll < x) {
  268. if (prevAll + x < _view) {
  269. return true;
  270. }
  271. x = -(prevAll - _view + _tab);
  272. } else {
  273. if (-x < contentW - nextAll) {
  274. return true;
  275. }
  276. x = -(contentW - nextAll - _tab);
  277. }
  278. doc.animate({
  279. left: x
  280. }, 100);
  281. return true;
  282. },
  283. buildIframe: function (url) { // 创建iframe窗口
  284. var $content = this.$content,
  285. iframeName = 'iframe-' + this.tabId, $checkedIframe;
  286. $content.children('.active').removeClass('active');
  287. $content.append('<iframe src="' + url + '" frameborder="0" name="' + iframeName + '" class="page-frame animation-fade active"></iframe>');
  288. $checkedIframe = $content.find('iframe[name="' + iframeName + '"]');
  289. $.site.iframeEvents($checkedIframe);
  290. },
  291. tabSize: function () { // 修改标签页盒子尺寸
  292. var content, $tabNav = $(".con-tabs"),
  293. _num = $tabNav.find("li").size();
  294. content = this.tabWidth * _num;
  295. $tabNav.css("width", content);
  296. },
  297. tabEvent: function (doc, media) { // 增删标签页的对应状态
  298. var content = $(".con-tabs").width(),
  299. _view = this.view, _tab = this.tabWidth;
  300. if (content > this.view) {
  301. this.tabPosition(doc, _tab, "left", _view, content, media);
  302. this.btnView('visible');
  303. } else {
  304. this.btnView('hide');
  305. }
  306. if (this.currentView < _view || this.currentContent > content) {
  307. this.tabPosition(doc, _tab, "right", _view, content, media);
  308. }
  309. this.currentView = _view;
  310. this.currentContent = content;
  311. },
  312. tabPosition: function (doc, width, dir, view, content, media) { // 标签页的位移
  313. var self = this,
  314. x = doc.position().left,
  315. callback = function (x) {
  316. var flag = x + width;
  317. if (flag > 0) {
  318. self.relative = x;
  319. return 0;
  320. } else {
  321. return x;
  322. }
  323. };
  324. if (dir === "left") {
  325. if (x <= view - content) {
  326. return false;
  327. }
  328. if (typeof media !== 'undefined') {
  329. x = view - content;
  330. } else {
  331. x = this.relative !== 0 ? x - width + this.relative : x - width;
  332. this.relative = 0;
  333. }
  334. } else if (dir === "right") {
  335. if (x === 0) {
  336. return false;
  337. }
  338. if (typeof media !== 'undefined') {
  339. x = content <= view ? 0 : view - content;
  340. } else {
  341. x = callback(x + width);
  342. }
  343. }
  344. doc.animate({
  345. left: x
  346. }, 100);
  347. },
  348. _throttle: function (fn, interval) { // 函数节流操作
  349. var _fn = fn,
  350. timer,
  351. firstTime = true;
  352. return function () {
  353. var args = arguments,
  354. self = this;
  355. if (firstTime) {
  356. _fn.apply(self, args);
  357. firstTime = false;
  358. }
  359. if (timer) {
  360. return false;
  361. }
  362. timer = setTimeout(function () {
  363. clearTimeout(timer);
  364. timer = null;
  365. _fn.apply(self, args);
  366. }, interval || 500);
  367. };
  368. },
  369. closeTab: function ($item) {
  370. var checkedTabId = $item.children('a').attr('target'), $checked = '',
  371. $nextLi = $item.next('li'),
  372. $content = this.$content;
  373. if ($item.is('.active')) { // 关闭选中标签
  374. if ($nextLi.size() > 0) {
  375. $checked = $nextLi;
  376. } else {
  377. $checked = $item.prev('li');
  378. }
  379. $checked.addClass("active");
  380. this.enable($checked);
  381. this._checkoutTab($checked.find('a'));
  382. }
  383. $item.remove();
  384. $content.children('[name="' + checkedTabId + '"]').remove();
  385. this._updateSetting(checkedTabId);
  386. this.tabSize();
  387. this.tabEvent($(".con-tabs"), 'media');
  388. },
  389. btnView: function (status) { // 标签页左右移动按钮状态
  390. var $siteContabs = $('.site-contabs'),
  391. $contabsLeftBtn = $siteContabs.children('button.pull-left'),
  392. $contabsRightBtn = $siteContabs.find('.pull-right > button.btn-icon');
  393. if (status === 'visible') {
  394. $contabsLeftBtn.removeClass('hide');
  395. $contabsRightBtn.removeClass('hide');
  396. } else if (status === 'hide') {
  397. $contabsLeftBtn.addClass('hide');
  398. $contabsRightBtn.addClass('hide');
  399. }
  400. }
  401. };
  402. })(window, document, jQuery);