Tabs 标签页
选项卡切换组件。
何时使用
提供平级的区域将大块内容进行收纳和展现,保持界面整洁。
Ant Design 依次提供了三级选项卡,分别用于不同的场景。
- 卡片式的页签,提供可关闭的样式,常用于容器顶部。
- 标准线条式页签,用于容器内部的主功能切换,这是最常用的 Tabs。
- RadioButton 可作为更次级的页签来使用。
代码演示
默认选中第一项。
<template>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1">Content of Tab Pane 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane>
</a-tabs>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
});
</script>
禁用某一项。
<template>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1">Tab 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2" disabled>Tab 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Tab 3</a-tab-pane>
</a-tabs>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
});
</script>
有图标的标签。
<template>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1">
<template #tab>
<span>
<apple-outlined />
Tab 1
</span>
</template>
Tab 1
</a-tab-pane>
<a-tab-pane key="2">
<template #tab>
<span>
<android-outlined />
Tab 2
</span>
</template>
Tab 2
</a-tab-pane>
</a-tabs>
</template>
<script lang="ts">
import { AppleOutlined, AndroidOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
components: {
AppleOutlined,
AndroidOutlined,
},
});
</script>
可以左右、上下滑动,容纳更多标签。
<template>
<div style="width: 500px">
<a-radio-group v-model:value="mode" :style="{ marginBottom: '8px' }">
<a-radio-button value="top">Horizontal</a-radio-button>
<a-radio-button value="left">Vertical</a-radio-button>
</a-radio-group>
<a-tabs
:tab-position="mode"
:style="{ height: '200px' }"
@prevClick="callback"
@nextClick="callback"
v-model:activeKey="activeKey"
>
<a-tab-pane v-for="i in 30" :key="i" :tab="`Tab-${i}`">Content of tab {{ i }}</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const mode = ref('top');
const activeKey = ref('1');
const callback = (val: string) => {
console.log(val);
};
return {
mode,
callback,
activeKey,
};
},
});
</script>
可以在页签右边添加附加操作。
<template>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1">Content of tab 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2">Content of tab 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of tab 3</a-tab-pane>
<template #tabBarExtraContent>
<a-button>Extra Action</a-button>
</template>
</a-tabs>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
});
</script>
大号页签用在页头区域,小号用在弹出框等较狭窄的容器内。
<template>
<div>
<a-radio-group v-model:value="size" style="margin-bottom: 16px">
<a-radio-button value="small">Small</a-radio-button>
<a-radio-button value="default">Default</a-radio-button>
<a-radio-button value="large">Large</a-radio-button>
</a-radio-group>
<a-tabs v-model:activeKey="activeKey" :size="size">
<a-tab-pane key="1" tab="Tab 1">Content of tab 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2">Content of tab 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of tab 3</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const size = ref('small');
const activeKey = ref('1');
return {
size,
activeKey,
};
},
});
</script>
有四个位置,tabPosition="left|right|top|bottom"
。
<template>
<div style="width: 500px">
<a-radio-group v-model:value="tabPosition" style="margin: 8px">
<a-radio-button value="top">top</a-radio-button>
<a-radio-button value="bottom">bottom</a-radio-button>
<a-radio-button value="left">left</a-radio-button>
<a-radio-button value="right">right</a-radio-button>
</a-radio-group>
<a-tabs v-model:activeKey="activeKey" :tab-position="tabPosition">
<a-tab-pane key="1" tab="Tab 1">Content of Tab 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2">Content of Tab 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of Tab 3</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const tabPosition = ref('top');
const activeKey = ref('1');
return {
tabPosition,
activeKey,
};
},
});
</script>
另一种样式的页签,不提供对应的垂直样式。
<template>
<a-tabs type="card" v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1">Content of Tab Pane 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2">Content of Tab Pane 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane>
</a-tabs>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
});
</script>
只有卡片样式的页签支持新增和关闭选项。 使用 :closable="false"
禁止关闭。
<template>
<a-tabs v-model:activeKey="activeKey" type="editable-card" @edit="onEdit">
<a-tab-pane v-for="pane in panes" :key="pane.key" :tab="pane.title" :closable="pane.closable">
{{ pane.content }}
</a-tab-pane>
</a-tabs>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const panes = ref([
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1' },
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
{ title: 'Tab 3', content: 'Content of Tab 3', key: '3', closable: false },
]);
const activeKey = ref(panes.value[0].key);
const newTabIndex = ref(0);
const callback = (key: string) => {
console.log(key);
};
const add = () => {
activeKey.value = `newTab${++newTabIndex.value}`;
panes.value.push({ title: 'New Tab', content: 'Content of new Tab', key: activeKey.value });
};
const remove = (targetKey: string) => {
let lastIndex = 0;
panes.value.forEach((pane, i) => {
if (pane.key === targetKey) {
lastIndex = i - 1;
}
});
panes.value = panes.value.filter(pane => pane.key !== targetKey);
if (panes.value.length && activeKey.value === targetKey) {
if (lastIndex >= 0) {
activeKey.value = panes.value[lastIndex].key;
} else {
activeKey.value = panes.value[0].key;
}
}
};
const onEdit = (targetKey: string | MouseEvent, action: string) => {
if (action === 'add') {
add();
} else {
remove(targetKey as string);
}
};
return {
panes,
activeKey,
callback,
onEdit,
};
},
});
</script>
用于容器顶部,需要一点额外的样式覆盖。
<template>
<div class="card-container">
<a-tabs v-model:activeKey="activeKey" type="card">
<a-tab-pane key="1" tab="Tab Title 1">
<p>Content of Tab Pane 1</p>
<p>Content of Tab Pane 1</p>
<p>Content of Tab Pane 1</p>
</a-tab-pane>
<a-tab-pane key="2" tab="Tab Title 2">
<p>Content of Tab Pane 2</p>
<p>Content of Tab Pane 2</p>
<p>Content of Tab Pane 2</p>
</a-tab-pane>
<a-tab-pane key="3" tab="Tab Title 3">
<p>Content of Tab Pane 3</p>
<p>Content of Tab Pane 3</p>
<p>Content of Tab Pane 3</p>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref(1),
};
},
});
</script>
<style>
.card-container {
background: #f5f5f5;
overflow: hidden;
padding: 24px;
}
.card-container > .ant-tabs-card > .ant-tabs-content {
height: 120px;
margin-top: -16px;
}
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
background: #fff;
padding: 16px;
}
.card-container > .ant-tabs-card > .ant-tabs-bar {
border-color: #fff;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
border-color: transparent;
background: transparent;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
border-color: #fff;
background: #fff;
}
</style>
隐藏默认的页签增加图标,给自定义触发器绑定事件。
<template>
<div>
<div :style="{ marginBottom: '16px' }">
<a-button @click="add">ADD</a-button>
</div>
<a-tabs v-model:activeKey="activeKey" hide-add type="editable-card" @edit="onEdit">
<a-tab-pane v-for="pane in panes" :key="pane.key" :tab="pane.title" :closable="pane.closable">
{{ pane.content }}
</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const panes = ref([
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1' },
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
]);
const activeKey = ref(panes.value[0].key);
const newTabIndex = ref(0);
const add = () => {
activeKey.value = `newTab${newTabIndex.value++}`;
panes.value.push({
title: `New Tab ${activeKey.value}`,
content: `Content of new Tab ${activeKey.value}`,
key: activeKey.value,
});
};
const remove = (targetKey: string) => {
let lastIndex = 0;
panes.value.forEach((pane, i) => {
if (pane.key === targetKey) {
lastIndex = i - 1;
}
});
panes.value = panes.value.filter(pane => pane.key !== targetKey);
if (panes.value.length && activeKey.value === targetKey) {
if (lastIndex >= 0) {
activeKey.value = panes.value[lastIndex].key;
} else {
activeKey.value = panes.value[0].key;
}
}
};
const onEdit = (targetKey: string) => {
remove(targetKey);
};
return {
panes,
activeKey,
onEdit,
add,
};
},
});
</script>
自定义页签头
<template>
<div>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1" style="height: 200px">Content of Tab Pane 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>
<a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane>
<template #renderTabBar="{ DefaultTabBar, ...props }">
<component
:is="DefaultTabBar"
v-bind="props"
:style="{ zIndex: 1, background: '#fff', textAlign: 'right' }"
/>
</template>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
return {
activeKey: ref('1'),
};
},
});
</script>
API
Tabs
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 |
animated | 是否使用动画切换 Tabs,在 tabPosition=top | bottom 时有效 | boolean | {inkBar:boolean, tabPane:boolean} | true, 当 type=”card” 时为 false |
defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 |
hideAdd | 是否隐藏加号图标,在 type=”editable-card” 时有效 | boolean | false |
size | 大小,提供 large default 和 small 三种大小 | string | ‘default’ |
tabBarExtraContent | tab bar 上额外的元素 | slot | 无 |
tabBarStyle | tab bar 的样式对象 | object | - |
tabPosition | 页签位置,可选值有 top right bottom left | string | ‘top’ |
type | 页签的基本样式,可选 line 、card editable-card 类型 | string | ‘line’ |
tabBarGutter | tabs 之间的间隙 | number | 无 |
事件
事件名称 | 说明 | 回调参数 |
---|---|---|
change | 切换面板的回调 | Function(activeKey) {} |
edit | 新增和删除页签的回调,在 type=”editable-card” 时有效 | (targetKey, action): void |
nextClick | next 按钮被点击的回调 | Function |
prevClick | prev 按钮被点击的回调 | Function |
tabClick | tab 被点击的回调 | Function |
Tabs.TabPane
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
key | 对应 activeKey | string | 无 |
tab | 选项卡头显示文字 | string|slot | 无 |