diff --git a/examples/tabs.html b/examples/tabs.html new file mode 100644 index 00000000..12241777 --- /dev/null +++ b/examples/tabs.html @@ -0,0 +1,236 @@ + + + + + + 标签页组件 - Layui + + + +
+
+ +
+
Tab Content-1
+
Tab Content-2
+
Tab Content-3
+
Tab Content-4
+
Tab Content-5
+
Tab Content-6
+
+
+ +
+ + + + + +
+ +
+ 方法渲染: +
+
+
+ +
卡片风格:
+ +
+ +
+
内容-1
+
内容-2
+
内容-3
+
内容-4
+
内容-5
+
内容-6
+
+
+ +
卡片 + 边框:
+ +
+ +
+
+
+ +
+
+
2
+
3
+
4
+
5
+
6
+
+
+ +
HASH:
+ +
+ +
+ +
标签嵌套:
+ +
+ +
+
+
+
    +
  • 标题 1-1
  • +
  • 标题 1-2
  • +
+
+
1-1
+
1-2
+
+
+
+
+
+
    +
  • 标题 2-1
  • +
  • 标题 2-2
  • +
  • 标题 2-3
  • +
+
+
2-1
+
2-2
+
2-3
+
+
+
+
3
+
4
+
5
+
+
+ +
+ 给任意元素添加 Tab 功能: +
+ + +
+ + + +
+
+
内容 111
+
内容 222
+
内容 333
+
+ +
+ +
+ + + + + diff --git a/src/css/layui.css b/src/css/layui.css index e579a630..536e2863 100644 --- a/src/css/layui.css +++ b/src/css/layui.css @@ -513,20 +513,56 @@ a cite{font-style: normal; *cursor:pointer;} .layui-col-space32>*{padding: 16px;} -/* 内边距 */ +/* + * 内边距 + */ .layui-padding-1{padding: 4px !important;} .layui-padding-2{padding: 8px !important;} .layui-padding-3{padding: 16px !important;} .layui-padding-4{padding: 32px !important;} .layui-padding-5{padding: 48px !important;} -/* 外边距 */ +/* 上下内边距 */ +.layui-py-xxs{padding: 5px 0;} +.layui-py-xs{padding: 8px 0;} +.layui-py-sm{padding: 11px 0;} +.layui-py-md, .layui-py{padding: 16px 0;} +.layui-py-lg{padding: 24px 0;} +.layui-py-xl{padding: 32px 0;} + +.layui-py-0{padding: 0;} +.layui-py-1{padding: 4px 0;} +.layui-py-2{padding: 8px 0;} +.layui-py-3{padding: 12px 0;} +.layui-py-4{padding: 16px 0;} +.layui-py-5{padding: 20px 0;} +.layui-py-5{padding: 24px 0;} + +/* + * 外边距 + */ .layui-margin-1{margin: 4px !important;} .layui-margin-2{margin: 8px !important;} .layui-margin-3{margin: 16px !important;} .layui-margin-4{margin: 32px !important;} .layui-margin-5{margin: 48px !important;} +/* 上下外边距 */ +.layui-my-xxs{margin: 5px 0;} +.layui-my-xs{margin: 8px 0;} +.layui-my-sm{margin: 11px 0;} +.layui-my-md, .layui-my{margin: 16px 0;} +.layui-my-lg{margin: 24px 0;} +.layui-my-xl{margin: 32px 0;} + +.layui-my-0{margin: 0;} +.layui-my-1{margin: 4px 0;} +.layui-my-2{margin: 8px 0;} +.layui-my-3{margin: 12px 0;} +.layui-my-4{margin: 16px 0;} +.layui-my-5{margin: 20px 0;} +.layui-my-5{margin: 24px 0;} + /* * 页面元素 @@ -1284,6 +1320,42 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh .layui-dropdown:before{content:""; position: absolute; width: 100%; height: 6px; left: 0; top: -6px;} .layui-dropdown-shade{top: 0; left: 0; width: 100%; height: 100%; _height: expression(document.body.offsetHeight+"px"); position: fixed; _position: absolute; pointer-events: auto;} + +/* Tabs 标签页 */ +.layui-tabs{position: relative;} +.layui-tabs *{box-sizing: border-box;} +.layui-tabs.layui-hide-v{overflow: hidden;} +.layui-tabs-header{position: relative; left: 0; height: 40px; white-space: nowrap; font-size: 0; transition: all .16s; -webkit-transition: all .16s;} +.layui-tabs-header:after, +.layui-tabs-scroll:after{content: ""; position: absolute; left: 0; bottom: 0; z-index: 0; width: 100%; border-bottom: 1px solid #eee;} +.layui-tabs-header li{position: relative; display: inline-block; vertical-align: middle; line-height: 40px; padding: 0 16px; text-align: center; cursor: pointer; font-size: 14px; transition: all .16s; -webkit-transition: all .16s;} +.layui-tabs-header li:first-child{margin-left: 0;} +.layui-tabs-header li a{display: block; padding: 0 16px; margin: 0 -16px;} +.layui-tabs-header .layui-this{color: #16baaa;} +.layui-tabs-header .layui-this:after{content: ""; position: absolute; left:0; top: 0; z-index: 1; width: 100%; height: 100%; border-bottom: 3px solid #16baaa; box-sizing: border-box; pointer-events: none;} +.layui-tabs-header .layui-badge, +.layui-tabs-header .layui-badge-dot{left: 5px; top: -1px;} + +.layui-tabs-scroll{position: relative; overflow: hidden; padding: 0 40px;} +.layui-tabs-scroll .layui-tabs-header:after{display: none; content: none; border: 0;} +.layui-tabs-bar .layui-icon{position: absolute; left: 0; top: 0; z-index: 3; width: 40px; height: 100%; line-height: 40px; border: 1px solid #eee; text-align: center; cursor: pointer; box-sizing: border-box; background-color: #fff; box-shadow: 2px 0 5px 0 rgb(0 0 0 / 6%);} +.layui-tabs-bar .layui-icon-next{left: auto; right: 0; box-shadow: -2px 0 5px 0 rgb(0 0 0 / 6%);} + +.layui-tabs-header li .layui-tabs-close{position: relative; display: inline-block; width: 16px; height: 16px; line-height: 18px; margin-left: 8px; top: 0px; text-align: center; font-size: 12px; color: #959595; border-radius: 50%; font-weight: 700; transition: all .16s; -webkit-transition: all .16s;} +.layui-tabs-header li .layui-tabs-close:hover{ background-color: #ff5722; color: #fff;} + +.layui-tabs-body{padding: 16px 0;} +.layui-tabs-item{display: none;} + +/* tabs 卡片风格 */ +.layui-tabs-card>.layui-tabs-header .layui-this{background-color: #fff;} +.layui-tabs-card>.layui-tabs-header .layui-this:after{border: 1px solid #eee; border-bottom-color: #fff; border-radius: 2px 2px 0 0;} +.layui-tabs-card>.layui-tabs-header li:first-child.layui-this:after{margin-left: -1px;} +.layui-tabs-card>.layui-tabs-header li:last-child.layui-this:after{margin-right: -1px;} +.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-top: 0; border-radius: 0;} +.layui-tabs-card.layui-panel>.layui-tabs-body{padding: 16px;} + + /** 导航菜单 **/ .layui-nav{position: relative; padding: 0 15px; background-color: #2f363c; color: #fff; border-radius: 2px; font-size: 0; box-sizing: border-box;} .layui-nav *{font-size: 14px;} diff --git a/src/layui.js b/src/layui.js index 7e92fb5a..e701bdce 100644 --- a/src/layui.js +++ b/src/layui.js @@ -62,6 +62,7 @@ tree: 'tree', // 树结构 table: 'table', // 表格 treeTable: 'treeTable', // 树表 + tabs: 'tabs', // 标签页 element: 'element', // 常用元素操作 rate: 'rate', // 评分组件 colorpicker: 'colorpicker', // 颜色选择器 @@ -71,6 +72,7 @@ util: 'util', // 工具块 code: 'code', // 代码修饰器 jquery: 'jquery', // DOM 库(第三方) + component: 'component', // 组件构建器 all: 'all', 'layui.all': 'layui.all' // 聚合标识(功能性的,非真实模块) @@ -257,8 +259,8 @@ // currentStyle.getAttribute 参数为 camelCase 形式的字符串 Layui.prototype.getStyle = function(node, name){ var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null); - return style.getPropertyValue - ? style.getPropertyValue(name) + return style.getPropertyValue + ? style.getPropertyValue(name) : style.getAttribute(name.replace(/-(\w)/g, function(_, c){ return c ? c.toUpperCase() : '';})); }; @@ -401,13 +403,14 @@ var data = { path: [], search: {}, - hash: (hash.match(/[^#](#.*$)/) || [])[1] || '' + hash: (hash.match(/[^#](#.*$)/) || [])[1] || '', + href: '' }; - if(!/^#\//.test(hash)) return data; // 禁止非路由规范 + if (!/^#/.test(hash)) return data; // 禁止非路由规范 - hash = hash.replace(/^#\//, ''); - data.href = '/' + hash; + hash = hash.replace(/^#/, ''); + data.href = hash; hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || []; // 提取 Hash 结构 diff --git a/src/modules/tabs.js b/src/modules/tabs.js new file mode 100644 index 00000000..358939e5 --- /dev/null +++ b/src/modules/tabs.js @@ -0,0 +1,622 @@ +/** + * tabs + * 标签页组件 + */ + +layui.define('component', function(exports) { + 'use strict'; + + var $ = layui.$; + + // 创建组件 + var component = layui.component({ + name: 'tabs', // 组件名 + + // 默认配置 + config: { + elem: '.layui-tabs', + trigger: 'click', // 触发事件 + headerMode: 'auto' // 标签头部的显示模式 + }, + + CONST: { + ELEM: 'layui-tabs', + HEADER: 'layui-tabs-header', + CLOSE: 'layui-tabs-close', + BODY: 'layui-tabs-body', + ITEM: 'layui-tabs-item', + CARD: 'layui-tabs-card', + TRIGGER_NAME: 'LAY_TABS_ELEM_callback' + }, + + isRenderOnEvent: false, + + // 渲染 + render: function() { + var that = this; + var options = that.config; + + // 标签页元素项 + that.elemHeader = ['.'+ component.CONST.HEADER + ':eq(0)', '>li']; + that.elemBody = ['.'+ component.CONST.BODY + ':eq(0)', '>.'+ component.CONST.ITEM]; + + // 获取头部和内容元素 + that.elemItem = function(){ + var thisElem = that.thisElem || options.elem; + return { + header: { + elem: thisElem.find(that.elemHeader[0]), + items: thisElem.find(that.elemHeader.join('')) + }, + body: { + elem: thisElem.find(that.elemBody[0]), + items: thisElem.find(that.elemBody.join('')) + } + }; + }; + + // 如果传入 header 参数 + if (layui.type(options.header) === 'array') { + if (options.header.length === 0) return; + + // 是否为元素绑定 + if (typeof options.header[0] === 'string') { + that.elemHeader = options.header.concat(); + that.thisElem = $('body'); + } else { // 方法传值渲染 + that.elemView = $('
'); + if (options.className) that.elemView.addClass(options.className); + + var elemHeader = $(''); + var elemBody = $('
'); + + // 生成标签项 + layui.each(options.header, function(i, item){ + var elemHeaderItem = that.renderHeaderItem(item); + elemHeader.append(elemHeaderItem); + }); + layui.each(options.body, function(i, item){ + var elemBodyItem = that.renderBodyItem(item); + elemBody.append(elemBodyItem); + }); + + that.elemView.append(elemHeader).append(elemBody); + options.elem.html(that.elemView); + } + } else { + that.renderClose(); // 初始化标签关闭结构 + } + + // 如果传入 body 参数 + if (layui.type(options.body) === 'array') { + if (typeof options.body[0] === 'string') { + that.thisElem = $('body'); + that.elemBody = options.body.concat(); + } + } + + // 初始选中项 + var data = that.data(); + if ('index' in options && data.index != options.index) { + that.change(that.findHeaderItem(options.index)); + } else if (data.index === -1) { + that.change(that.findHeaderItem(0)); + } + + // 初始化滚动结构 + that.roll('auto'); + + // 清除隐藏占位 + if (options.elem.hasClass(component.CONST.CLASS_HIDEV)) { + options.elem.removeClass(component.CONST.CLASS_HIDEV); + } + + // 回调 + typeof options.ready === 'function' && options.ready(data); + layui.event.call(options.elem[0], component.CONST.MOD_NAME, 'ready('+ options.id +')', data); // 事件 + }, + + // 事件 + events: function() { + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var TRIGGER_NAME = component.CONST.TRIGGER_NAME; + var thisElem = that.thisElem ? elemItem.header.elem : options.elem; + + // 移除重复事件 + if (thisElem.data(TRIGGER_NAME)) { + thisElem.off(options.trigger, thisElem.data(TRIGGER_NAME)); + } + + // 点击标签头部 + var elemHeaderItem = that.thisElem ? that.elemHeader[1] : that.elemHeader.join(''); + thisElem.data(TRIGGER_NAME, function(){ + that.change($(this)); + }).on(options.trigger, elemHeaderItem, thisElem.data(TRIGGER_NAME)); + + // resize 事件 + if (!inner.onresize) { + var timer; + $(window).on('resize', function(){ + clearTimeout(timer); + timer = setTimeout(function(){ + layui.each(component.cache.id, function(key){ + var that = component.getThis(key); + if(!that) return; + that.roll('init'); + }); + },50); + }); + inner.onresize = true; + } + }, + + // 实例接口 + inst: {}, + + // 扩展接口 + exports: { + // 增加标签 + add: function(id, obj) { + var that = component.getThis(id); + if(!that) return this; + that.add(obj); + }, + + // 关闭单个标签 + close: function(id, index) { + var that = component.getThis(id); + if(!that) return this; + if(index === undefined) index = that.data().index; // index 若不传,则表示关闭当前标签 + that.close(that.findHeaderItem(index)); + }, + + // 关闭多个标签。若传 index,则按 index 所在标签为事件执行关闭操作 + closeMore: function(id, type, index) { + var that = component.getThis(id); + if(!that) return this; + that.closeMore(type, index); + }, + + // 切换标签 + change: function(id, index) { + var that = component.getThis(id); + if(!that) return this; + that.change(that.findHeaderItem(index)); + }, + + // 获取标签信息 + data: function(id) { + var that = component.getThis(id); + return that ? that.data() : {}; + }, + + // 获取标签指定头部项 + headerItem: function(id, index) { + var that = component.getThis(id); + return that ? that.findHeaderItem(index) : this; + }, + + // 获取标签指定头部项 + bodyItem: function(id, index) { + var that = component.getThis(id); + return that ? that.findBodyItem(index) : this; + }, + + // 调整视图结构 + setView: function(id) { + var that = component.getThis(id); + if (!that) return this; + that.roll('auto'); + } + } + }); + + var inner = {}; + var Class = component.Class; + + // 增加标签 + Class.prototype.add = function(obj){ + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var newHeaderItem = that.renderHeaderItem(obj); + var newBodyItem = that.renderBodyItem(obj); + + // 插入方式 + if (obj.mode === 'curr') { // 在当前标签后插入 + var data = that.data(); + data.thisHeader.after(newHeaderItem); + data.thisBody.after(newBodyItem); + } else { + var mode = ({ + prepend: 'prepend' + ,append: 'append' + })[obj.mode || 'append'] || 'append'; + elemItem.header.elem[mode](newHeaderItem); + elemItem.body.elem[mode](newBodyItem); + } + + // 将插入项切换为当前标签 + that.change(newHeaderItem); + + // 回调 + var params = that.data(); + typeof obj.done === 'function' && obj.done(params); + typeof options.add === 'function' && options.add(params); + layui.event.call(newHeaderItem[0], component.CONST.MOD_NAME, 'add('+ options.id +')', params); // 事件 + }; + + // 关闭指定标签 + Class.prototype.close = function(thisHeader) { + if(!thisHeader || !thisHeader[0]) return; + + var that = this; + var options = that.config; + var index = thisHeader.index(); + + if (!thisHeader[0]) return; + + // 不可关闭项 + if (thisHeader.attr('lay-unclosed')) return; + + // 如果关闭的是当前标签,则更换当前标签下标 + if (thisHeader.hasClass(component.CONST.CLASS_THIS)) { + if (thisHeader.next()[0]) { + that.change(thisHeader.next()); + } else if(thisHeader.prev()[0]) { + that.change(thisHeader.prev()); + } + } + + // 移除元素 + thisHeader.remove(); + that.findBodyItem(index).remove(); + + that.roll('auto', index); + + // 回调 + var params = that.data(); + typeof options.close === 'function' && options.close(params); + layui.event.call(params.thisHeader[0], component.CONST.MOD_NAME, 'close('+ options.id +')', params); // 事件 + }; + + // 批量关闭标签 + Class.prototype.closeMore = function(type, index) { + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var data = that.data(); + var headers = elemItem.header.items; + var bodys = elemItem.body.items; + var FILTER = ':not([lay-unclosed])'; + + index = index === undefined ? data.index : index; + + // 遍历 + headers.each(function(i){ + var othis = $(this); + var unclosed = othis.attr('lay-unclosed'); + + // 标注不可关闭项 + if (unclosed) { + bodys.eq(i).attr('lay-unclosed', unclosed); + } + }); + + // 移交当前标签项 + if (!data.thisHeader.attr('lay-unclosed')) { + if(type === 'all' || !type){ + var nextHeader = headers.filter(':gt('+ data.index +')[lay-unclosed]').eq(0); + var prevHeader = $(headers.filter(':lt('+ data.index +')[lay-unclosed]').get().reverse()).eq(0); + if (nextHeader[0]) { + that.change(nextHeader); + } else if(prevHeader[0]) { + that.change(prevHeader); + } + } else if(index !== data.index) { + that.change(that.findHeaderItem(index)); + } + } + + // 执行批量关闭标签 + if (type === 'other') { // 关闭其他标签 + headers.eq(index).siblings(FILTER).remove(); + bodys.eq(index).siblings(FILTER).remove(); + } else if(type === 'right') { // 关闭右侧标签 + headers.filter(':gt('+ index +')'+ FILTER).remove(); + bodys.filter(':gt('+ index +')'+ FILTER).remove(); + } else { // 关闭所有标签 + headers.filter(FILTER).remove(); + bodys.filter(FILTER).remove(); + } + + // 回调 + var params = that.data(); + typeof options.close === 'function' && options.close(params); + layui.event.call(params.thisHeader[0], component.CONST.MOD_NAME, 'close('+ options.id +')', params); // 事件 + }; + + // 切换标签 + Class.prototype.change = function(thisHeader) { + if (!thisHeader || !thisHeader[0]) return; + + var that = this; + var options = that.config; + var index = thisHeader.index(); + var thatA = thisHeader.find('a'); + var isLink = typeof thatA.attr('href') === 'string' && thatA.attr('target') === '_blank'; // 是否存在跳转链接 + var unselect = typeof thisHeader.attr('lay-unselect') === 'string'; // 是否禁用选中 + + // 执行切换 + if (!(isLink || unselect)) { + // 头部 + thisHeader.addClass(component.CONST.CLASS_THIS).siblings() + .removeClass(component.CONST.CLASS_THIS); + // 内容 + that.findBodyItem(index).addClass(component.CONST.CLASS_SHOW) + .siblings().removeClass(component.CONST.CLASS_SHOW); + } + + that.roll('auto', index); + + // 回调 + var params = that.data(); + typeof options.change === 'function' && options.change(params); + layui.event.call(thisHeader[0], component.CONST.MOD_NAME, 'change('+ options.id +')', params); // 事件 + }; + + // 渲染标签头部项 + Class.prototype.renderHeaderItem = function(obj){ + var that = this; + var options = that.config; + var elemItem = $(obj.headerItem || options.headerItem || '
  • '); + + elemItem.html(obj.title || 'New Tab'); + + // 追加属性 + layui.each(obj, function(key, value){ + if(/^(title|content|mode|done)$/.test(key)) return; + elemItem.attr('lay-'+ key, value); + }); + + // 追加标签关闭元素 + that.appendClose(elemItem, obj); + + return elemItem; + }; + + // 渲染标签内容项 + Class.prototype.renderBodyItem = function(obj) { + var that = this + var options = that.config + var elemItem = $(obj.bodyItem || options.bodyItem || '
    '); + + elemItem.html(obj.content || ''); + return elemItem; + }; + + // 给某一个标签项追加可关闭元素 + Class.prototype.appendClose = function(othis, obj) { + var that = this + var options = that.config; + + if(!options.closable) return; + + obj = obj || {}; + if (obj.unclosed || othis.attr('lay-unclosed')) return; // 不可关闭项 + + if (!othis.find('.'+ component.CONST.CLOSE)[0]) { + var close = $(''); + close.on('click', function(){ + that.close($(this).parent()); + return false; + }); + othis.append(close); + } + }; + + // 渲染标签可关闭元素 + Class.prototype.renderClose = function(othis) { + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var hasDel = that.cache('close'); + + // 是否开启关闭 + if (options.closable) { + if (!hasDel) { + elemItem.header.items.each(function(){ + that.appendClose($(this)); + }); + that.cache('close', true); + } + } else if(hasDel) { + elemItem.header.items.each(function() { + $(this).find('.'+ component.CONST.CLOSE).remove(); + }); + } + }; + + // 滚动标签 + Class.prototype.roll = function(type, index) { + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var headerElem = elemItem.header.elem; + var headerItems = elemItem.header.items; + var scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度 + var outerWidth = Math.ceil(headerElem.outerWidth()); // 可视区域的长度 + var tabsLeft = headerElem.data('left') || 0; + var scrollMode = options.headerMode === 'scroll'; // 标签头部是否始终保持滚动模式 + + // 让选中标签始终保持在可视区域 + var rollToVisibleArea = function() { + index = isNaN(index) ? that.data().index : index; + + var thisItemElem = headerItems.eq(index); + if (!thisItemElem[0]) return; + + // 当前标签的相对水平坐标值 + var thisLeft = Math.ceil(thisItemElem.position().left); + var padding = 1; // 让边界额外保持一定间距 + + // 当选中标签溢出在可视区域「左侧」时 + var countWidth = thisLeft - (thisItemElem.prev().outerWidth() || 0); // 始终空出上一个标签 + if (countWidth > 0) countWidth = countWidth - padding; + + // 左侧临界值 + if (tabsLeft + countWidth < 0) { + tabsLeft = countWidth >= 0 ? countWidth : 0; // 标签的复原位移不能超出 0 + return headerElem.css('left', -tabsLeft).data('left', -tabsLeft);; + } + + // 当选中标签溢出在可视区域「右侧」时, + var countWidth = thisLeft + thisItemElem.outerWidth() + + (thisItemElem.next().outerWidth() || 0) + padding; // 始终空出下一个标签 + + // 右侧临界值 + if (tabsLeft + countWidth - outerWidth > 0) { + tabsLeft = countWidth - outerWidth; + headerElem.css('left', -tabsLeft).data('left', -tabsLeft); + } + }; + + // css 类名 + var CLASS_SCROLL = 'layui-tabs-scroll'; + var CLASS_BAR = 'layui-tabs-bar'; + var CLASS_BAR_ICON = ['layui-icon-prev', 'layui-icon-next']; + + // 滚动结构 + var rollElem = { + elem: $('
    '), + bar: $([ + '
    ', + '', + '', + '
    ' + ].join('')) + }; + + // 不渲染头部滚动结构 + if (options.headerMode === 'normal') return; + + // 是否渲染滚动结构 + var elemScroll = headerElem.parent('.'+ CLASS_SCROLL); + if (scrollMode || (!scrollMode && scrollWidth > outerWidth)) { + if (!elemScroll[0]) { + if (options.elem.hasClass(component.CONST.CARD)) { + rollElem.elem.addClass(component.CONST.CARD); + } + headerElem.wrap(rollElem.elem); + headerElem.after(rollElem.bar); + + // 点击左右箭头 + rollElem.bar.children().on('click', function(){ + var othis = $(this); + var mode = othis.attr('lay-mode'); + if ($(this).hasClass(component.CONST.CLASS_DISABLED)) return; + mode && that.roll(mode); + }); + } + } else if(!scrollMode) { + if (elemScroll[0]) { + elemScroll.find('.'+ CLASS_BAR).remove(); + headerElem.unwrap().css('left', 0).data('left', 0); + } else { + return; + } + } + + if (type === 'init') return; + + // 重新获取 + scrollWidth = headerElem.prop('scrollWidth') // 实际总长度 + outerWidth = headerElem.outerWidth() // 可视区域的长度 + elemScroll = headerElem.parent('.'+ CLASS_SCROLL); + + // 左箭头(往右滚动) + if (type === 'prev') { + // 当前的 left 减去可视宽度,用于与上一轮的页签比较 + var prevLeft = -tabsLeft - outerWidth; + if(prevLeft < 0) prevLeft = 0; + headerItems.each(function(i, item){ + var li = $(item); + var left = Math.ceil(li.position().left); + + if (left >= prevLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } else if(type === 'auto') { // 自动识别滚动 + rollToVisibleArea(); + } else { // 右箭头(往左滚动) + headerItems.each(function(i, item){ + var li = $(item); + var left = Math.ceil(li.position().left); + + if (left + li.outerWidth() >= outerWidth - tabsLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } + + // 同步箭头状态 + tabsLeft = headerElem.data('left') || 0; + + // 左 + elemScroll.find('.'+ CLASS_BAR_ICON[0])[ + tabsLeft < 0 ? 'removeClass' : 'addClass' + ](component.CONST.CLASS_DISABLED); + // 右 + elemScroll.find('.'+ CLASS_BAR_ICON[1])[ + parseFloat(tabsLeft + scrollWidth) - outerWidth > 0 + ? 'removeClass' + : 'addClass' + ](component.CONST.CLASS_DISABLED); + }; + + // 根据 id 或 index 获取相关标签头部项 + Class.prototype.findHeaderItem = function(index) { + if(!( + typeof index === 'number' + || (typeof index === 'string' && index) + )) return; + var headerItems = this.elemItem().header.items; + var item = headerItems.filter('[lay-id="'+ index +'"]'); + return item[0] ? item : headerItems.eq(index); + }; + + // 根据 index 获取相关标签内容项 + Class.prototype.findBodyItem = function(index) { + return this.elemItem().body.items.eq(index); + }; + + // 返回给回调的公共信息 + Class.prototype.data = function() { + var that = this; + var options = that.config; + var elemItem = that.elemItem(); + var thisHeader = elemItem.header.items.filter('.'+ component.CONST.CLASS_THIS); + var index = thisHeader.index(); + + return { + options: options, // 标签配置信息 + elemItem: elemItem, + thisHeader: thisHeader, // 当前标签头部项 + thisBody: that.findBodyItem(index), // 当前标签内容项 + index: index, // 当前标签下标 + length: elemItem.header.items.length // 当前标签数 + } + }; + + // 初始化渲染 + $(function() { + component.render(); + }); + + exports(component.CONST.MOD_NAME, component); +});