Skip to content

标签页 Tabs

选项卡切换组件

何时使用

  • 提供平级的区域将大块内容进行收纳和展现,保持界面整洁

基本使用

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
function onChange(key: string | number) {
  console.log('key', key)
}
</script>
<template>
  <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" @change="onChange" />
</template>

卡片式标签页

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
function onChange(key: string | number) {
  console.log('key', key)
}
</script>
<template>
  <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" type="card" @change="onChange" />
</template>

禁用某一项

禁用 key: 3 标签页


Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPagesDisabled = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    disabled: true,
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
</script>
<template>
  <Flex vertical>
    <Tabs :tab-pages="tabPagesDisabled" v-model:active-key="activeKey" />
    <Tabs :tab-pages="tabPagesDisabled" v-model:active-key="activeKey" type="card" />
  </Flex>
</template>

居中展示

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
</script>
<template>
  <Flex vertical>
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" centered />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" centered type="card" />
  </Flex>
</template>

带图标的标签页

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, h, watchEffect } from 'vue'
import { AppleOutlined, AndroidOutlined, WindowsOutlined } from '@ant-design/icons-vue'
const iconTabPages = ref([
  {
    tab: 'Tab 1',
    icon: h(AppleOutlined),
    content: 'Content of Tab Pane 1'
  },
  {
    tab: 'Tab 2',
    icon: h(AndroidOutlined),
    content: 'Content of Tab Pane 2'
  },
  {
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const iconActiveKey = ref(0)
watchEffect(() => {
  console.log('iconActiveKey', iconActiveKey.value)
})
</script>
<template>
  <Flex vertical>
    <Tabs :tab-pages="iconTabPages" v-model:active-key="iconActiveKey" />
    <Tabs :tab-pages="iconTabPages" v-model:active-key="iconActiveKey" type="card">
      <template #tab="{ key, tab }">
        <AppleOutlined v-if="key === 0" />
        <AndroidOutlined v-if="key === 1" />
        {{ tab }}
        <WindowsOutlined v-if="key === 2" />
      </template>
    </Tabs>
  </Flex>
</template>

前缀 & 后缀

prefix
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
suffix
Content of Tab Pane 1
prefix
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
suffix
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
</script>
<template>
  <Flex vertical>
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" prefix="prefix" suffix="suffix" />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" type="card">
      <template #prefix>
        <Button type="primary">prefix</Button>
      </template>
      <template #suffix>
        <Button type="primary">suffix</Button>
      </template>
    </Tabs>
  </Flex>
</template>

三种尺寸

small
middle
large
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
const sizeOptions = [
  {
    label: 'small',
    value: 'small'
  },
  {
    label: 'middle',
    value: 'middle'
  },
  {
    label: 'large',
    value: 'large'
  }
]
const size = ref('middle')
</script>
<template>
  <Flex vertical>
    <Radio :options="sizeOptions" v-model:value="size" button button-style="solid" />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" :size="size" />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" :size="size" type="card" />
  </Flex>
</template>

自定义位置

top
bottom
left
right
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
const positionOptions = [
  {
    label: 'top',
    value: 'top'
  },
  {
    label: 'bottom',
    value: 'bottom'
  },
  {
    label: 'left',
    value: 'left'
  },
  {
    label: 'right',
    value: 'right'
  }
]
const position = ref('top')
</script>
<template>
  <Flex vertical>
    <Radio :options="sizeOptions" v-model:value="size" button button-style="solid" />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" :size="size" />
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" :size="size" type="card" />
  </Flex>
</template>

左右滑动,容纳更多标签

top
bottom
left
right
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Tab 7
Tab 8
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Tab 7
Tab 8
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect, computed } from 'vue'
const moreTabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  },
  {
    key: '7',
    tab: 'Tab 7',
    content: 'Content of Tab Pane 7'
  },
  {
    key: '8',
    tab: 'Tab 8',
    content: 'Content of Tab Pane 8'
  }
])
const moreActiveKey = ref('1')
const positionOptions = [
  {
    label: 'top',
    value: 'top'
  },
  {
    label: 'bottom',
    value: 'bottom'
  },
  {
    label: 'left',
    value: 'left'
  },
  {
    label: 'right',
    value: 'right'
  }
]
const morePosition = ref('top')
const positionStyle = computed(() => {
  if (['top', 'bottom'].includes(morePosition.value)) {
    return {
      width: '360px'
    }
  } else {
    return {
      height: '200px'
    }
  }
})
watchEffect(() => {
  console.log('moreActiveKey', moreActiveKey.value)
})
</script>
<template>
  <Flex vertical>
    <Radio :options="positionOptions" v-model:value="morePosition" button button-style="solid" />
    <Tabs
      :style="positionStyle"
      :tab-pages="moreTabPages"
      v-model:active-key="moreActiveKey"
      :tab-position="morePosition"
    />
    <Tabs
      :style="positionStyle"
      :tab-pages="moreTabPages"
      v-model:active-key="moreActiveKey"
      :tab-position="morePosition"
      type="card"
    />
  </Flex>
</template>

自定义 Tab & Content 样式

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
</script>
<template>
  <Flex vertical>
    <Tabs
      :tab-pages="tabPages"
      v-model:active-key="activeKey"
      :tab-gutter="24"
      :tab-style="{
        background: '#fff7e6',
        fontSize: '16px',
        color: '#ff6900',
        fontWeight: 600
      }"
      :content-style="{
        fontSize: '16px'
      }"
    />
    <Tabs
      :tab-pages="tabPages"
      v-model:active-key="activeKey"
      type="card"
      size="large"
      :tab-gutter="12"
      :tab-style="{
        background: '#fff7e6',
        fontSize: '16px',
        color: '#ff6900',
        fontWeight: 600
      }"
      :content-style="{
        fontSize: '16px'
      }"
    />
  </Flex>
</template>

自定义内容

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6

key: 1 的 slot 内容

Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
</script>
<template>
  <Tabs :tab-pages="tabPages" v-model:active-key="activeKey">
    <template #content="{ key, content }">
      <p v-if="key === '1'">key: 1 的 slot 内容</p>
      <p v-if="key === '2'">key: 2 的 slot 内容</p>
      <p v-if="key === '3'">key: 3 的 slot 内容</p>
    </template>
  </Tabs>
</template>

标签页配置器

Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
Content of Tab Pane 1
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tabPages = ref([
  {
    key: '1',
    tab: 'Tab 1',
    content: 'Content of Tab Pane 1'
  },
  {
    key: '2',
    tab: 'Tab 2',
    content: 'Content of Tab Pane 2'
  },
  {
    key: '3',
    tab: 'Tab 3',
    content: 'Content of Tab Pane 3'
  },
  {
    key: '4',
    tab: 'Tab 4',
    content: 'Content of Tab Pane 4'
  },
  {
    key: '5',
    tab: 'Tab 5',
    content: 'Content of Tab Pane 5'
  },
  {
    key: '6',
    tab: 'Tab 6',
    content: 'Content of Tab Pane 6'
  }
])
const activeKey = ref('1')
watchEffect(() => {
  console.log('activeKey', activeKey.value)
})
const typeOptions = [
  {
    label: 'line',
    value: 'line'
  },
  {
    label: 'card',
    value: 'card'
  }
]
const sizeOptions = [
  {
    label: 'small',
    value: 'small'
  },
  {
    label: 'middle',
    value: 'middle'
  },
  {
    label: 'large',
    value: 'large'
  }
]
const positionOptions = [
  {
    label: 'top',
    value: 'top'
  },
  {
    label: 'bottom',
    value: 'bottom'
  },
  {
    label: 'left',
    value: 'left'
  },
  {
    label: 'right',
    value: 'right'
  }
]
const state = reactive({
  prefix: '',
  suffix: '',
  animated: true,
  centered: false,
  size: 'middle',
  type: 'line',
  tabGutter: 24,
  tabPosition: 'top'
})
</script>
<template>
  <Flex gap="large" vertical>
    <Row :gutter="[24, 12]">
      <Col :span="6">
        <Space gap="small" vertical> prefix:<Input v-model:value="state.prefix" placeholder="prefix" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> suffix:<Input v-model:value="state.suffix" placeholder="suffix" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> animated:<Switch v-model="state.animated" /> </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical> centered:<Switch v-model="state.centered" /> </Space>
      </Col>
      <Col :span="12">
        <Space gap="small" vertical>
          size:<Radio :options="sizeOptions" v-model:value="state.size" button button-style="solid" />
        </Space>
      </Col>
      <Col :span="6">
        <Space gap="small" vertical>
          type:<Radio :options="typeOptions" v-model:value="state.type" button button-style="solid" />
        </Space>
      </Col>
      <Col :span="6">
        <Flex gap="small" vertical>
          tabGutter:<Slider v-model:value="state.tabGutter" :min="0" :step="1" :max="100" />
        </Flex>
      </Col>
      <Col :span="12">
        <Space gap="small" vertical>
          tabPosition:<Radio
            :options="positionOptions"
            v-model:value="state.tabPosition"
            button
            button-style="solid"
          />
        </Space>
      </Col>
    </Row>
    <Tabs :tab-pages="tabPages" v-model:active-key="activeKey" v-bind="state" />
  </Flex>
</template>

APIs

Tabs

参数说明类型默认值
tabPages标签页数组Tab[][]
prefix标签页前缀string | slotundefined
suffix标签页后缀string | slotundefined
animated是否启用切换动画,在 tabPosition: 'top' | 'bottom' 时有效booleantrue
centered标签是否居中展示booleanfalse
size标签页大小'small' | 'middle' | 'large''middle'
type标签页的类型'line' | 'card''line'
tabGutter页签之前的间隙大小,单位 pxnumberundefined
tabStyle自定义页签样式CSSProperties{}
tabPosition自定义页签位置'top' | 'right' | 'bottom' | 'left''top'
contentStyle自定义内容样式CSSProperties{}
activeKey
v-model
当前激活 tab 面板的 keystring | numberundefined

Tab Type

名称说明类型默认值
key?对应 activeKey,如果没有传入 key 属性,则默认使用数据索引 (0,1,2...) 绑定string | numberundefined
tab?页签显示文字stringundefined
icon?页签图标VNodeundefined
content?标签页内容string | slotundefined
disabled?是否禁用页签booleanfalse

Events

名称说明类型
change切换面板的回调(key: string | number) => void

Released under the MIT License.