2016-12-05 18:04:30 +08:00
|
|
|
<template>
|
2016-12-06 22:51:06 +08:00
|
|
|
<div :class="classes">
|
|
|
|
<div :class="[prefixCls + '-bar']">
|
|
|
|
<div :class="[prefixCls + '-nav-container']">
|
|
|
|
<div :class="[prefixCls + '-nav-wrap']">
|
|
|
|
<div :class="[prefixCls + '-nav-scroll']">
|
2017-03-03 13:38:46 +08:00
|
|
|
<div :class="[prefixCls + '-nav']" ref="nav">
|
2016-12-06 22:51:06 +08:00
|
|
|
<div :class="barClasses" :style="barStyle"></div>
|
2017-03-03 13:38:46 +08:00
|
|
|
<div :class="tabCls(item)" v-for="(item, index) in navList" @click="handleChange(index)">
|
2016-12-06 22:51:06 +08:00
|
|
|
<Icon v-if="item.icon !== ''" :type="item.icon"></Icon>
|
|
|
|
{{ item.label }}
|
2017-03-03 13:38:46 +08:00
|
|
|
<Icon v-if="showClose(item)" type="ios-close-empty" @click.native.stop="handleRemove(index)"></Icon>
|
2016-12-06 22:51:06 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
2017-03-27 13:28:37 +08:00
|
|
|
<div :class="[prefixCls + '-nav-right']" v-if="showSlot"><slot name="right"></slot></div>
|
2016-12-06 22:51:06 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div :class="contentClasses" :style="contentStyle"><slot></slot></div>
|
|
|
|
</div>
|
2016-12-05 18:04:30 +08:00
|
|
|
</template>
|
|
|
|
<script>
|
2016-12-06 22:51:06 +08:00
|
|
|
import Icon from '../icon/icon.vue';
|
|
|
|
import { oneOf, getStyle } from '../../utils/assist';
|
|
|
|
|
|
|
|
const prefixCls = 'ivu-tabs';
|
|
|
|
|
2016-12-05 18:04:30 +08:00
|
|
|
export default {
|
2017-03-03 13:38:46 +08:00
|
|
|
name: 'Tabs',
|
2016-12-06 22:51:06 +08:00
|
|
|
components: { Icon },
|
|
|
|
props: {
|
2017-03-03 13:38:46 +08:00
|
|
|
value: {
|
2016-12-06 22:51:06 +08:00
|
|
|
type: [String, Number]
|
|
|
|
},
|
|
|
|
type: {
|
|
|
|
validator (value) {
|
|
|
|
return oneOf(value, ['line', 'card']);
|
|
|
|
},
|
|
|
|
default: 'line'
|
|
|
|
},
|
|
|
|
size: {
|
|
|
|
validator (value) {
|
|
|
|
return oneOf(value, ['small', 'default']);
|
|
|
|
},
|
|
|
|
default: 'default'
|
|
|
|
},
|
|
|
|
animated: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
closable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
}
|
|
|
|
},
|
2016-12-05 18:04:30 +08:00
|
|
|
data () {
|
2016-12-06 22:51:06 +08:00
|
|
|
return {
|
|
|
|
prefixCls: prefixCls,
|
|
|
|
navList: [],
|
|
|
|
barWidth: 0,
|
2017-03-03 13:38:46 +08:00
|
|
|
barOffset: 0,
|
2017-03-27 13:28:37 +08:00
|
|
|
activeKey: this.value,
|
|
|
|
showSlot:false
|
2016-12-25 22:49:42 +08:00
|
|
|
};
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
classes () {
|
|
|
|
return [
|
|
|
|
`${prefixCls}`,
|
|
|
|
{
|
|
|
|
[`${prefixCls}-card`]: this.type === 'card',
|
|
|
|
[`${prefixCls}-mini`]: this.size === 'small' && this.type === 'line',
|
|
|
|
[`${prefixCls}-no-animation`]: !this.animated
|
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
];
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
contentClasses () {
|
|
|
|
return [
|
|
|
|
`${prefixCls}-content`,
|
2016-12-06 23:11:44 +08:00
|
|
|
{
|
|
|
|
[`${prefixCls}-content-animated`]: this.animated
|
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
];
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
barClasses () {
|
|
|
|
return [
|
|
|
|
`${prefixCls}-ink-bar`,
|
2016-12-06 23:11:44 +08:00
|
|
|
{
|
|
|
|
[`${prefixCls}-ink-bar-animated`]: this.animated
|
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
];
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
contentStyle () {
|
2017-03-03 13:38:46 +08:00
|
|
|
const x = this.navList.findIndex((nav) => nav.name === this.activeKey);
|
2016-12-06 22:51:06 +08:00
|
|
|
const p = x === 0 ? '0%' : `-${x}00%`;
|
|
|
|
|
|
|
|
let style = {};
|
|
|
|
if (x > -1) {
|
|
|
|
style = {
|
|
|
|
transform: `translateX(${p}) translateZ(0px)`
|
2016-12-25 22:49:42 +08:00
|
|
|
};
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
|
|
|
return style;
|
|
|
|
},
|
|
|
|
barStyle () {
|
|
|
|
let style = {
|
|
|
|
display: 'none',
|
2016-12-06 23:11:44 +08:00
|
|
|
width: `${this.barWidth}px`
|
2016-12-06 22:51:06 +08:00
|
|
|
};
|
|
|
|
if (this.type === 'line') style.display = 'block';
|
2016-12-06 23:11:44 +08:00
|
|
|
if (this.animated) {
|
|
|
|
style.transform = `translate3d(${this.barOffset}px, 0px, 0px)`;
|
|
|
|
} else {
|
|
|
|
style.left = `${this.barOffset}px`;
|
|
|
|
}
|
2016-12-06 22:51:06 +08:00
|
|
|
|
|
|
|
return style;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
getTabs () {
|
|
|
|
return this.$children.filter(item => item.$options.name === 'TabPane');
|
|
|
|
},
|
|
|
|
updateNav () {
|
|
|
|
this.navList = [];
|
|
|
|
this.getTabs().forEach((pane, index) => {
|
|
|
|
this.navList.push({
|
|
|
|
label: pane.label,
|
|
|
|
icon: pane.icon || '',
|
2017-03-03 13:38:46 +08:00
|
|
|
name: pane.currentName || index,
|
2017-01-16 14:36:53 +08:00
|
|
|
disabled: pane.disabled,
|
|
|
|
closable: pane.closable
|
2016-12-06 22:51:06 +08:00
|
|
|
});
|
2017-03-03 13:38:46 +08:00
|
|
|
if (!pane.currentName) pane.currentName = index;
|
2016-12-06 22:51:06 +08:00
|
|
|
if (index === 0) {
|
2017-03-03 13:38:46 +08:00
|
|
|
if (!this.activeKey) this.activeKey = pane.currentName || index;
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
|
|
|
});
|
2016-12-06 23:11:44 +08:00
|
|
|
this.updateStatus();
|
2016-12-06 22:51:06 +08:00
|
|
|
this.updateBar();
|
|
|
|
},
|
|
|
|
updateBar () {
|
|
|
|
this.$nextTick(() => {
|
2017-03-03 13:38:46 +08:00
|
|
|
const index = this.navList.findIndex((nav) => nav.name === this.activeKey);
|
|
|
|
const prevTabs = this.$refs.nav.querySelectorAll(`.${prefixCls}-tab`);
|
2016-12-06 22:51:06 +08:00
|
|
|
const tab = prevTabs[index];
|
|
|
|
this.barWidth = parseFloat(getStyle(tab, 'width'));
|
|
|
|
|
|
|
|
if (index > 0) {
|
|
|
|
let offset = 0;
|
|
|
|
const gutter = this.size === 'small' ? 0 : 16;
|
|
|
|
for (let i = 0; i < index; i++) {
|
|
|
|
offset += parseFloat(getStyle(prevTabs[i], 'width')) + gutter;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.barOffset = offset;
|
|
|
|
} else {
|
|
|
|
this.barOffset = 0;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2016-12-06 23:11:44 +08:00
|
|
|
updateStatus () {
|
|
|
|
const tabs = this.getTabs();
|
2017-03-03 13:38:46 +08:00
|
|
|
tabs.forEach(tab => tab.show = (tab.currentName === this.activeKey) || this.animated);
|
2016-12-06 23:11:44 +08:00
|
|
|
},
|
2016-12-06 22:51:06 +08:00
|
|
|
tabCls (item) {
|
|
|
|
return [
|
|
|
|
`${prefixCls}-tab`,
|
|
|
|
{
|
|
|
|
[`${prefixCls}-tab-disabled`]: item.disabled,
|
2017-03-03 13:38:46 +08:00
|
|
|
[`${prefixCls}-tab-active`]: item.name === this.activeKey
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
];
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
handleChange (index) {
|
|
|
|
const nav = this.navList[index];
|
|
|
|
if (nav.disabled) return;
|
2017-03-03 13:38:46 +08:00
|
|
|
this.activeKey = nav.name;
|
|
|
|
this.$emit('input', nav.name);
|
|
|
|
this.$emit('on-click', nav.name);
|
2016-12-06 22:51:06 +08:00
|
|
|
},
|
|
|
|
handleRemove (index) {
|
|
|
|
const tabs = this.getTabs();
|
|
|
|
const tab = tabs[index];
|
2017-03-23 11:03:43 +08:00
|
|
|
tab.$destroy();
|
2016-12-06 22:51:06 +08:00
|
|
|
|
2017-03-03 13:38:46 +08:00
|
|
|
if (tab.currentName === this.activeKey) {
|
2016-12-06 22:51:06 +08:00
|
|
|
const newTabs = this.getTabs();
|
|
|
|
let activeKey = -1;
|
|
|
|
|
|
|
|
if (newTabs.length) {
|
|
|
|
const leftNoDisabledTabs = tabs.filter((item, itemIndex) => !item.disabled && itemIndex < index);
|
|
|
|
const rightNoDisabledTabs = tabs.filter((item, itemIndex) => !item.disabled && itemIndex > index);
|
|
|
|
|
|
|
|
if (rightNoDisabledTabs.length) {
|
2017-03-03 13:38:46 +08:00
|
|
|
activeKey = rightNoDisabledTabs[0].currentName;
|
2016-12-06 22:51:06 +08:00
|
|
|
} else if (leftNoDisabledTabs.length) {
|
2017-03-03 13:38:46 +08:00
|
|
|
activeKey = leftNoDisabledTabs[leftNoDisabledTabs.length - 1].currentName;
|
2016-12-06 22:51:06 +08:00
|
|
|
} else {
|
2017-03-03 13:38:46 +08:00
|
|
|
activeKey = newTabs[0].currentName;
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.activeKey = activeKey;
|
2017-03-23 11:03:43 +08:00
|
|
|
this.$emit('input', activeKey);
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
2017-03-03 13:38:46 +08:00
|
|
|
this.$emit('on-tab-remove', tab.currentName);
|
2016-12-06 22:51:06 +08:00
|
|
|
this.updateNav();
|
2017-01-16 14:36:53 +08:00
|
|
|
},
|
|
|
|
showClose (item) {
|
|
|
|
if (this.type === 'card') {
|
|
|
|
if (item.closable !== null) {
|
|
|
|
return item.closable;
|
|
|
|
} else {
|
|
|
|
return this.closable;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
2017-03-03 13:38:46 +08:00
|
|
|
value (val) {
|
|
|
|
this.activeKey = val;
|
|
|
|
},
|
2016-12-06 22:51:06 +08:00
|
|
|
activeKey () {
|
|
|
|
this.updateBar();
|
2017-01-11 15:41:23 +08:00
|
|
|
this.updateStatus();
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
2017-03-27 13:28:37 +08:00
|
|
|
},
|
|
|
|
mounted(){
|
|
|
|
this.showSlot = this.$slots.default !== undefined;
|
2016-12-06 22:51:06 +08:00
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
};
|
|
|
|
</script>
|