mirror of https://github.com/layui/layui
821 lines
25 KiB
JavaScript
821 lines
25 KiB
JavaScript
import layui from '../core.js';
|
|
import $ from 'jquery';
|
|
import { component as component$1 } from './component.js';
|
|
|
|
/**
|
|
* tabs
|
|
* 标签页组件
|
|
*/
|
|
|
|
|
|
// 创建组件
|
|
var component = component$1({
|
|
name: 'tabs', // 组件名
|
|
|
|
// 默认配置
|
|
config: {
|
|
elem: '.layui-tabs',
|
|
trigger: 'click', // 标签切换的触发事件
|
|
headerMode: 'auto' // 标签头部的显示模式 auto | scroll | normal
|
|
},
|
|
|
|
CONST: {
|
|
ELEM: 'layui-tabs',
|
|
HEADER: 'layui-tabs-header',
|
|
CLOSE: 'layui-tabs-close',
|
|
BODY: 'layui-tabs-body',
|
|
ITEM: 'layui-tabs-item',
|
|
CARD: 'layui-tabs-card'
|
|
},
|
|
|
|
// 渲染
|
|
render: function() {
|
|
var that = this;
|
|
var options = that.config;
|
|
|
|
// 标签页元素项
|
|
that.headerElem = ['.'+ component.CONST.HEADER + ':eq(0)', '>li'];
|
|
that.bodyElem = ['.'+ component.CONST.BODY + ':eq(0)', '>.'+ component.CONST.ITEM];
|
|
|
|
// 获取标签容器中的 header body 相关元素
|
|
that.getContainer = function() {
|
|
var elem = that.documentElem || options.elem;
|
|
return {
|
|
header: {
|
|
elem: elem.find(that.headerElem[0]),
|
|
items: elem.find(that.headerElem.join(''))
|
|
},
|
|
body: {
|
|
elem: elem.find(that.bodyElem[0]),
|
|
items: elem.find(that.bodyElem.join(''))
|
|
}
|
|
};
|
|
};
|
|
|
|
// 若 header 选项类型为数组
|
|
if (layui.type(options.header) === 'array') {
|
|
// if (options.header.length === 0) return;
|
|
|
|
// 给任意元素绑定 tabs 切换功能
|
|
if (typeof options.header[0] === 'string') {
|
|
that.headerElem = options.header.concat();
|
|
that.documentElem = $(document);
|
|
} else { // 方法传值渲染
|
|
that.elemView = $('<div class="layui-tabs"></div>');
|
|
if (options.className) that.elemView.addClass(options.className);
|
|
|
|
var headerElem = $('<ul class="layui-tabs-header"></ul>');
|
|
var bodyElem = $('<div class="layui-tabs-body"></div>');
|
|
|
|
// 生成标签项
|
|
layui.each(options.header, function(i, item){
|
|
var elemHeaderItem = that.renderHeaderItem(item);
|
|
headerElem.append(elemHeaderItem);
|
|
});
|
|
layui.each(options.body, function(i, item){
|
|
var elemBodyItem = that.renderBodyItem(item);
|
|
bodyElem.append(elemBodyItem);
|
|
});
|
|
|
|
that.elemView.append(headerElem).append(bodyElem);
|
|
options.elem.html(that.elemView);
|
|
}
|
|
} else {
|
|
that.renderClose(); // 初始化标签关闭结构
|
|
}
|
|
|
|
// 若 body 选项类型为数组
|
|
if (layui.type(options.body) === 'array') {
|
|
if (typeof options.body[0] === 'string') {
|
|
that.documentElem = $(document);
|
|
that.bodyElem = options.body.concat();
|
|
}
|
|
}
|
|
|
|
// 初始选中项
|
|
var data = that.data();
|
|
if ('index' in options && data.index != options.index) {
|
|
that.change(that.findHeaderItem(options.index), true);
|
|
} else if (data.index === -1) { // 初始选中项为空时,默认选中第一个
|
|
that.change(that.findHeaderItem(0), true);
|
|
}
|
|
|
|
// 初始化滚动结构
|
|
that.roll('auto');
|
|
|
|
// 清除隐藏占位
|
|
if (options.elem.hasClass(component.CONST.CLASS_HIDEV)) {
|
|
options.elem.removeClass(component.CONST.CLASS_HIDEV);
|
|
}
|
|
|
|
// 回调
|
|
typeof options.afterRender === 'function' && options.afterRender(data);
|
|
|
|
// 渲染成功后的事件
|
|
layui.event.call(
|
|
options.elem[0],
|
|
component.CONST.MOD_NAME,
|
|
'afterRender('+ options.id +')',
|
|
data
|
|
);
|
|
},
|
|
|
|
// 事件
|
|
events: function() {
|
|
var that = this;
|
|
var options = that.config;
|
|
var container = that.getContainer();
|
|
var MOD_NAME = component.CONST.MOD_NAME;
|
|
var TRIGGER_NAMESPACE = '.lay_'+ MOD_NAME + '_trigger';
|
|
var delegatedElement = that.documentElem ? container.header.elem : options.elem;
|
|
|
|
// 标签头部事件
|
|
var trigger = options.trigger + TRIGGER_NAMESPACE;
|
|
var elemHeaderItem = that.documentElem ? that.headerElem[1] : that.headerElem.join('');
|
|
delegatedElement.off(trigger).on(trigger, elemHeaderItem, function() {
|
|
that.change($(this));
|
|
});
|
|
|
|
// 窗口 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.getInst(key);
|
|
if(!that) return;
|
|
that.roll('init');
|
|
});
|
|
}, 50);
|
|
});
|
|
inner.onresize = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
// 内部变量集
|
|
var inner = {};
|
|
|
|
/**
|
|
* 扩展组件原型方法
|
|
*/
|
|
|
|
var Class = component.Class;
|
|
|
|
/**
|
|
* 增加标签
|
|
* @param {Object} opts
|
|
* @param {string} opts.title - 标签标题
|
|
* @param {string} opts.content - 标签内容
|
|
* @param {string} opts.id - 标签的 lay-id 属性值
|
|
* @param {string} [opts.index] - 活动标签索引,默认取当前选中标签的索引
|
|
* @param {('append'|'prepend'|'after'|'before')} [opts.mode='append'] - 标签插入方式
|
|
* @param {boolean} [opts.active] - 是否将新增项设置为活动标签
|
|
* @param {boolean} [opts.closable] - 标签是否可关闭。初始值取决于 options.closable
|
|
* @param {string} [opts.headerItem] - 自定义标签头部元素
|
|
* @param {string} [opts.bodyItem] - 自定义标签内容元素
|
|
* @param {Function} [opts.done] - 标签添加成功后执行的回调函数
|
|
*/
|
|
Class.prototype.add = function(opts) {
|
|
var that = this;
|
|
that.config;
|
|
var container = that.getContainer();
|
|
var newHeaderItem = that.renderHeaderItem(opts);
|
|
var newBodyItem = that.renderBodyItem(opts);
|
|
var data = that.data();
|
|
|
|
// 选项默认值
|
|
opts = $.extend({
|
|
active: true
|
|
}, opts);
|
|
|
|
// 插入方式
|
|
if (/(before|after)/.test(opts.mode)) { // 在活动标签前后插入
|
|
var hasOwnIndex = opts.hasOwnProperty('index');
|
|
var headerItem = hasOwnIndex ? that.findHeaderItem(opts.index) : data.thisHeaderItem;
|
|
var bodyItem = hasOwnIndex ? that.findBodyItem(opts.index) : data.thisHeaderItem;
|
|
headerItem[opts.mode](newHeaderItem);
|
|
bodyItem[opts.mode](newBodyItem);
|
|
} else { // 在标签最前后插入
|
|
var mode = ({
|
|
prepend: 'prepend', // 插入标签到最前
|
|
append: 'append' // 插入标签到最后
|
|
})[opts.mode || 'append'] || 'append';
|
|
container.header.elem[mode](newHeaderItem);
|
|
container.body.elem[mode](newBodyItem);
|
|
}
|
|
|
|
// 是否将新增项设置为活动标签
|
|
if (opts.active) {
|
|
that.change(newHeaderItem, true);
|
|
} else {
|
|
that.roll('auto');
|
|
}
|
|
|
|
// 回调
|
|
typeof opts.done === 'function' && opts.done(
|
|
$.extend(data, {
|
|
headerItem: newHeaderItem,
|
|
bodyItem: newBodyItem
|
|
})
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 关闭指定标签
|
|
* @param {Object} thisHeaderItem - 当前标签头部项元素
|
|
* @param {boolean} force - 是否强制删除
|
|
*/
|
|
Class.prototype.close = function(thisHeaderItem, force) {
|
|
if (!thisHeaderItem || !thisHeaderItem[0]) return;
|
|
|
|
var that = this;
|
|
var options = that.config;
|
|
var layid = thisHeaderItem.attr('lay-id');
|
|
var index = thisHeaderItem.index();
|
|
|
|
// 标签是否不可关闭
|
|
if (thisHeaderItem.attr('lay-closable') === 'false') {
|
|
return;
|
|
}
|
|
|
|
// 当前标签相关数据
|
|
var data = that.data();
|
|
|
|
// 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭
|
|
if (!force) {
|
|
var closable = layui.event.call(
|
|
thisHeaderItem[0],
|
|
component.CONST.MOD_NAME,
|
|
'beforeClose('+ options.id +')',
|
|
$.extend(data, {
|
|
index: index
|
|
})
|
|
);
|
|
|
|
// 是否阻止关闭
|
|
if (closable === false) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 如果关闭的是当前标签,则更换当前标签索引
|
|
if (thisHeaderItem.hasClass(component.CONST.CLASS_THIS)) {
|
|
if (thisHeaderItem.next()[0]) {
|
|
that.change(thisHeaderItem.next(), true);
|
|
} else if(thisHeaderItem.prev()[0]) {
|
|
that.change(thisHeaderItem.prev(), true);
|
|
}
|
|
}
|
|
|
|
// 移除元素
|
|
that.findBodyItem(layid || index).remove();
|
|
thisHeaderItem.remove();
|
|
|
|
that.roll('auto', index);
|
|
|
|
// 获取当前标签相关数据
|
|
var data = that.data();
|
|
|
|
// 标签关闭后的事件
|
|
layui.event.call(
|
|
data.thisHeaderItem[0],
|
|
component.CONST.MOD_NAME,
|
|
'afterClose('+ options.id +')',
|
|
data
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 批量关闭标签
|
|
* @see tabs.close
|
|
*/
|
|
Class.prototype.closeMult = function(mode, index) {
|
|
var that = this;
|
|
var options = that.config;
|
|
var container = that.getContainer();
|
|
var data = that.data();
|
|
var headers = container.header.items;
|
|
container.body.items;
|
|
var DISABLED_CLOSE_SELECTOR = '[lay-closable="false"]'; // 不可关闭标签选择器
|
|
|
|
index = index === undefined ? data.index : index;
|
|
|
|
var headerItem = that.findHeaderItem(index);
|
|
that.findBodyItem(index);
|
|
var itemIndex = headerItem.index();
|
|
|
|
// 若当前选中标签也允许关闭,则尝试寻找不可关闭的标签并将其选中
|
|
if (data.thisHeaderItem.attr('lay-closable') !== 'false') {
|
|
if(mode === 'all' || !mode){
|
|
var nextHeader = headers.filter(':gt('+ data.index +')'+ DISABLED_CLOSE_SELECTOR).eq(0);
|
|
var prevHeader = $(headers.filter(':lt('+ data.index +')'+ DISABLED_CLOSE_SELECTOR).get().reverse()).eq(0);
|
|
if (nextHeader[0]) {
|
|
that.change(nextHeader, true);
|
|
} else if(prevHeader[0]) {
|
|
that.change(prevHeader, true);
|
|
}
|
|
} else if(index !== data.index) { // 自动切换到活动标签
|
|
that.change(headerItem, true);
|
|
}
|
|
}
|
|
|
|
// 执行批量关闭标签
|
|
headers.each(function(i) {
|
|
var $this = $(this);
|
|
var layid = $this.attr('lay-id');
|
|
var bodyItem = that.findBodyItem(layid || i);
|
|
|
|
// 标签是否不可关闭
|
|
if ($this.attr('lay-closable') === 'false') {
|
|
return;
|
|
}
|
|
|
|
// 批量关闭方式
|
|
var isCloseOther = mode === 'other' && i !== itemIndex; // 关闭其他标签
|
|
var isCloseRight = mode === 'right' && i > itemIndex; // 关闭右侧标签
|
|
var isCloseLeft = mode === 'left' && i < itemIndex; // 关闭左侧标签(不推荐)
|
|
var isCloseAll = mode === 'all'; // 关闭所有标签
|
|
|
|
if (isCloseOther || isCloseRight || isCloseLeft || isCloseAll) {
|
|
$this.remove();
|
|
bodyItem.remove();
|
|
}
|
|
});
|
|
|
|
that.roll('auto');
|
|
|
|
// 回调
|
|
var data = that.data();
|
|
|
|
// 标签关闭后的事件
|
|
layui.event.call(
|
|
data.thisHeaderItem[0],
|
|
component.CONST.MOD_NAME,
|
|
'afterClose('+ options.id +')',
|
|
data
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 切换标签
|
|
* @param {Object} thisHeaderItem - 当前标签头部项元素
|
|
* @param {boolean} [force=false] - 是否强制切换
|
|
* @returns
|
|
*/
|
|
Class.prototype.change = function(thisHeaderItem, force) {
|
|
if (!thisHeaderItem || !thisHeaderItem[0]) return;
|
|
|
|
var that = this;
|
|
var options = that.config;
|
|
var layid = thisHeaderItem.attr('lay-id');
|
|
var index = thisHeaderItem.index();
|
|
var thatA = thisHeaderItem.find('a');
|
|
// 是否存在跳转链接
|
|
var isLink = typeof thatA.attr('href') === 'string' && thatA.attr('target') === '_blank';
|
|
// 是否不允许选中
|
|
var unselect = typeof thisHeaderItem.attr('lay-unselect') === 'string';
|
|
|
|
// 不满足切换的条件
|
|
if (isLink || unselect) {
|
|
return;
|
|
}
|
|
|
|
// 当前标签相关数据
|
|
var data = that.data();
|
|
|
|
// 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭
|
|
if (!force) {
|
|
var enable = layui.event.call(
|
|
thisHeaderItem[0],
|
|
component.CONST.MOD_NAME,
|
|
'beforeChange('+ options.id +')',
|
|
$.extend(data, {
|
|
from: {
|
|
index: data.index,
|
|
headerItem: data.thisHeaderItem
|
|
},
|
|
to: {
|
|
index: index,
|
|
headerItem: thisHeaderItem
|
|
}
|
|
})
|
|
);
|
|
|
|
// 是否阻止切换
|
|
if (enable === false) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 执行标签头部切换
|
|
thisHeaderItem.addClass(component.CONST.CLASS_THIS).siblings()
|
|
.removeClass(component.CONST.CLASS_THIS);
|
|
|
|
// 执行标签内容切换
|
|
that.findBodyItem(layid || index).addClass(component.CONST.CLASS_SHOW)
|
|
.siblings().removeClass(component.CONST.CLASS_SHOW);
|
|
|
|
that.roll('auto', index);
|
|
|
|
// 重新获取标签相关数据
|
|
var data = that.data();
|
|
|
|
// 标签切换后的事件
|
|
layui.event.call(
|
|
data.thisHeaderItem[0],
|
|
component.CONST.MOD_NAME,
|
|
'afterChange('+ options.id +')',
|
|
data
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 渲染标签头部项
|
|
* @param {Object} opts - 标签项配置信息
|
|
*/
|
|
Class.prototype.renderHeaderItem = function(opts) {
|
|
var that = this;
|
|
var options = that.config;
|
|
var headerItem = $(opts.headerItem || options.headerItem || '<li></li>');
|
|
|
|
headerItem.html(opts.title || 'New Tab').attr('lay-id', opts.id);
|
|
that.appendClose(headerItem, opts); // 追加标签关闭元素
|
|
return headerItem;
|
|
};
|
|
|
|
/**
|
|
* 渲染标签内容项
|
|
* @param {Object} opts - 标签项配置信息
|
|
*/
|
|
Class.prototype.renderBodyItem = function(opts) {
|
|
var that = this;
|
|
var options = that.config;
|
|
var bodyItem = $(opts.bodyItem || options.bodyItem || '<div class="'+ component.CONST.ITEM +'"></div>');
|
|
|
|
bodyItem.html(opts.content || '').attr('lay-id', opts.id);
|
|
return bodyItem;
|
|
};
|
|
|
|
/**
|
|
* 给某一个标签项追加可关闭元素
|
|
* @param {Object} headerItem - 标签项元素
|
|
* @param {Object} opts - 标签项配置信息
|
|
*/
|
|
Class.prototype.appendClose = function(headerItem, opts) {
|
|
var that = this;
|
|
var options = that.config;
|
|
|
|
if (!options.closable) return;
|
|
|
|
opts = opts || {};
|
|
|
|
// 不可关闭项
|
|
if (opts.closable == false) {
|
|
headerItem.attr('lay-closable', 'false');
|
|
}
|
|
|
|
if (headerItem.attr('lay-closable') === 'false') {
|
|
return;
|
|
}
|
|
|
|
// 可关闭项追加关闭按钮
|
|
if (!headerItem.find('.'+ component.CONST.CLOSE)[0]) {
|
|
var close = $('<i class="layui-icon layui-icon-close layui-unselect '+ component.CONST.CLOSE +'"></i>');
|
|
close.on('click', function(){
|
|
that.close($(this).parent());
|
|
return false;
|
|
});
|
|
headerItem.append(close);
|
|
}
|
|
};
|
|
|
|
// 渲染标签可关闭元素
|
|
Class.prototype.renderClose = function() {
|
|
var that = this;
|
|
var options = that.config;
|
|
var container = that.getContainer();
|
|
|
|
container.header.items.each(function() {
|
|
var $this = $(this);
|
|
// 是否开启关闭
|
|
if (options.closable) {
|
|
that.appendClose($this);
|
|
} else {
|
|
$this.find('.'+ component.CONST.CLOSE).remove();
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 标签头滚动
|
|
* @param {('auto'|'prev'|'next'|'init')} [mode='next'] - 滚动方式
|
|
* @param {number} index - 标签索引。默认取当前选中标签的索引值
|
|
* @returns
|
|
*/
|
|
Class.prototype.roll = function(mode, index) {
|
|
var that = this;
|
|
var options = that.config;
|
|
var container = that.getContainer();
|
|
var headerElem = container.header.elem;
|
|
var headerItems = container.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: $('<div class="'+ CLASS_SCROLL +' layui-border-box layui-unselect"></div>'),
|
|
bar: $([
|
|
'<div class="'+ CLASS_BAR +'">',
|
|
'<i class="layui-icon '+ CLASS_BAR_ICON[0] +'" lay-mode="prev"></i>',
|
|
'<i class="layui-icon '+ CLASS_BAR_ICON[1] +'" lay-mode="next"></i>',
|
|
'</div>'
|
|
].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 (mode === 'init') return;
|
|
|
|
// 重新获取
|
|
scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度
|
|
outerWidth = headerElem.outerWidth(); // 可视区域的长度
|
|
elemScroll = headerElem.parent('.'+ CLASS_SCROLL);
|
|
|
|
// 左箭头(往右滚动)
|
|
if (mode === '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(mode === 'auto') { // 自动识别滚动
|
|
rollToVisibleArea();
|
|
} else { // 右箭头(往左滚动) 默认 next
|
|
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);
|
|
};
|
|
|
|
/**
|
|
* 获取标签头部项
|
|
* @param {number|string} index - 标签索引或 lay-id
|
|
*/
|
|
Class.prototype.findHeaderItem = function(index) {
|
|
var container = this.getContainer();
|
|
var headerItems = container.header.items;
|
|
|
|
// 根据 lay-id 匹配
|
|
if (typeof index === 'string') {
|
|
return headerItems.filter('[lay-id="'+ index +'"]');
|
|
}
|
|
|
|
return headerItems.eq(index);
|
|
};
|
|
|
|
/**
|
|
* 获取标签内容项
|
|
* @param {number|string} index - 标签索引或 lay-id
|
|
*/
|
|
Class.prototype.findBodyItem = function(index) {
|
|
var container = this.getContainer();
|
|
var bodyItems = container.body.items;
|
|
|
|
// 根据 lay-id 匹配
|
|
if (typeof index === 'string') {
|
|
var bodyItem = bodyItems.filter('[lay-id="'+ index +'"]');
|
|
return bodyItem[0] ? bodyItem : function() {
|
|
// 若未匹配到 lay-id 对应内容项,则通过对应头部项的索引匹配内容项
|
|
var headerItems = container.header.items;
|
|
var headerItemIndex = headerItems.filter('[lay-id="'+ index +'"]').index();
|
|
|
|
return headerItemIndex !== -1 ? bodyItems.eq(headerItemIndex) : bodyItem;
|
|
}();
|
|
}
|
|
|
|
return bodyItems.eq(index);
|
|
};
|
|
|
|
/**
|
|
* 返回给回调的公共信息
|
|
* @returns
|
|
*/
|
|
Class.prototype.data = function() {
|
|
var that = this;
|
|
var options = that.config;
|
|
var container = that.getContainer();
|
|
var thisHeaderItem = container.header.items.filter('.'+ component.CONST.CLASS_THIS);
|
|
var index = thisHeaderItem.index();
|
|
var layid = thisHeaderItem.attr('lay-id');
|
|
|
|
return {
|
|
options: options, // 标签配置信息
|
|
container: container, // 标签容器的相关元素
|
|
thisHeaderItem: thisHeaderItem, // 当前活动标签头部项
|
|
thisBodyItem: that.findBodyItem(layid || index), // 当前活动标签内容项
|
|
index: index, // 当前活动标签索引
|
|
length: container.header.items.length // 标签数量
|
|
};
|
|
};
|
|
|
|
// 扩展组件接口
|
|
$.extend(component, {
|
|
/**
|
|
* 添加标签
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {Object} opts - 添加标签的配置项,详见 Class.prototype.add
|
|
*/
|
|
add: function(id, opts) {
|
|
var that = component.getInst(id);
|
|
if(!that) return;
|
|
that.add(opts);
|
|
},
|
|
|
|
/**
|
|
* 关闭标签
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {number} index - 标签索引
|
|
* @param {boolean} [force=false] - 是否强制关闭
|
|
*/
|
|
close: function(id, index, force) {
|
|
var that = component.getInst(id);
|
|
if (!that) return;
|
|
// index 若不传,则表示关闭当前标签
|
|
if (index === undefined) {
|
|
index = that.data().index;
|
|
}
|
|
that.close(that.findHeaderItem(index), force);
|
|
},
|
|
|
|
/**
|
|
* 关闭多个标签
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {('other'|'right'|'all')} [mode="all"] - 关闭方式
|
|
* @param {number} index - 活动标签的索引,默认取当前选中标签的索引。一般用于标签右键事件
|
|
*/
|
|
closeMult: function(id, mode, index) {
|
|
var that = component.getInst(id);
|
|
if(!that) return;
|
|
that.closeMult(mode, index);
|
|
},
|
|
|
|
/**
|
|
* 切换标签
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {number} index - 标签索引
|
|
*/
|
|
change: function(id, index, force) {
|
|
var that = component.getInst(id);
|
|
if(!that) return;
|
|
that.change(that.findHeaderItem(index), force);
|
|
},
|
|
|
|
/**
|
|
* 获取标签信息
|
|
* @param {string} id - 渲染时的实例 ID
|
|
*/
|
|
data: function(id) {
|
|
var that = component.getInst(id);
|
|
return that ? that.data() : {};
|
|
},
|
|
|
|
/**
|
|
* 获取标签指定头部项
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {number} index - 标签索引或 lay-id 值
|
|
* @returns
|
|
*/
|
|
getHeaderItem: function(id, index) {
|
|
var that = component.getInst(id);
|
|
if(!that) return;
|
|
return that.findHeaderItem(index);
|
|
},
|
|
|
|
/**
|
|
* 获取标签指定内容项
|
|
* @param {string} id - 渲染时的实例 ID
|
|
* @param {number} index - 标签索引或 lay-id 值
|
|
* @returns
|
|
*/
|
|
getBodyItem: function(id, index) {
|
|
var that = component.getInst(id);
|
|
if(!that) return;
|
|
return that.findBodyItem(index);
|
|
},
|
|
|
|
/**
|
|
* 刷新标签视图结构
|
|
* @param {string} id - 渲染时的实例 ID
|
|
*/
|
|
refresh: function(id) {
|
|
var that = component.getInst(id);
|
|
if (!that) return;
|
|
that.roll('auto');
|
|
}
|
|
});
|
|
|
|
// 初始化渲染
|
|
$(function() {
|
|
component.render();
|
|
});
|
|
|
|
export { component as default, component as tabs };
|
|
//# sourceMappingURL=tabs.js.map
|