开发预览 更新于 2026-05-10

Tabs 标签页

三种视觉变体的 tabs,支持受控与非受控、items 数组式 API、对齐方式可控。

基础用法

items 数组定义 tab 列表,v-model 绑定当前激活值。默认 variant="line",激活项底部带 accent 色横线。

背景 视口
在「账户」页面,可以修改昵称、头像、邮箱。
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const tab = ref('account');
const items = [
  { value: 'account', label: '账户' },
  { value: 'security', label: '安全' },
  { value: 'notifications', label: '通知' },
  { value: 'billing', label: '账单', disabled: true },
];
</script>
<template>
  <CfTabs v-model="tab" :items="items">
    <template #default="{ active }">
      <div v-if="active === 'account'">在「账户」页面,可以修改昵称、头像、邮箱。</div>
      <div v-if="active === 'security'">在「安全」页面,可以重置密码、启用两步验证。</div>
      <div v-if="active === 'notifications'">在「通知」页面,可以选择哪些事件推送邮件。</div>
    </template>
  </CfTabs>
</template>
<script setup>
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const tab = ref('account');
const items = [
  { value: 'account', label: '账户' },
  { value: 'security', label: '安全' },
  { value: 'notifications', label: '通知' },
  { value: 'billing', label: '账单', disabled: true },
];
</script>
<template>
  <CfTabs v-model="tab" :items="items">
    <template #default="{ active }">
      <div v-if="active === 'account'">在「账户」页面,可以修改昵称、头像、邮箱。</div>
      <div v-if="active === 'security'">在「安全」页面,可以重置密码、启用两步验证。</div>
      <div v-if="active === 'notifications'">在「通知」页面,可以选择哪些事件推送邮件。</div>
    </template>
  </CfTabs>
</template>
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [tab, setTab] = useState('account');
  const items = [
    { value: 'account', label: '账户' },
    { value: 'security', label: '安全' },
    { value: 'notifications', label: '通知' },
    { value: 'billing', label: '账单', disabled: true },
  ];
  return (
    <>
      <CfTabs value={tab} onChange={setTab} items={items}>
            <div v-if="active === 'account'">在「账户」页面,可以修改昵称、头像、邮箱。</div>
            <div v-if="active === 'security'">在「安全」页面,可以重置密码、启用两步验证。</div>
            <div v-if="active === 'notifications'">在「通知」页面,可以选择哪些事件推送邮件。</div>
    </>
  );
}
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [tab, setTab] = useState('account');
  const items = [
    { value: 'account', label: '账户' },
    { value: 'security', label: '安全' },
    { value: 'notifications', label: '通知' },
    { value: 'billing', label: '账单', disabled: true },
  ];
  return (
    <>
      <CfTabs value={tab} onChange={setTab} items={items}>
            <div v-if="active === 'account'">在「账户」页面,可以修改昵称、头像、邮箱。</div>
            <div v-if="active === 'security'">在「安全」页面,可以重置密码、启用两步验证。</div>
            <div v-if="active === 'notifications'">在「通知」页面,可以选择哪些事件推送邮件。</div>
    </>
  );
}

视觉变体

line 是默认下划线样式;segmented 是按钮组式分段控件;pill 是胶囊形单选式。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const a = ref('one');
const b = ref('one');
const c = ref('one');
const items = [
  { value: 'one', label: '一' },
  { value: 'two', label: '二' },
  { value: 'three', label: '三' },
];
</script>
<template>
  <div class="demo-stack">
    <CfTabs v-model="a" :items="items" variant="line" />
    <CfTabs v-model="b" :items="items" variant="segmented" />
    <CfTabs v-model="c" :items="items" variant="pill" />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const a = ref('one');
const b = ref('one');
const c = ref('one');
const items = [
  { value: 'one', label: '一' },
  { value: 'two', label: '二' },
  { value: 'three', label: '三' },
];
</script>
<template>
  <div class="demo-stack">
    <CfTabs v-model="a" :items="items" variant="line" />
    <CfTabs v-model="b" :items="items" variant="segmented" />
    <CfTabs v-model="c" :items="items" variant="pill" />
  </div>
</template>
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('one');
  const [a, setA] = useState('one');
  const items = [
    { value: 'one', label: '一' },
    { value: 'two', label: '二' },
    { value: 'three', label: '三' },
  ];
  const [b, setB] = useState('one');
  const [b, setB] = useState('one');
  const [c, setC] = useState('one');
  const [c, setC] = useState('one');
  return (
    <>
      <CfTabs value={a} onChange={setA} items={items} variant="line" />
      <CfTabs value={b} onChange={setB} items={items} variant="segmented" />
      <CfTabs value={c} onChange={setC} items={items} variant="pill" />
    </>
  );
}
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('one');
  const [a, setA] = useState('one');
  const items = [
    { value: 'one', label: '一' },
    { value: 'two', label: '二' },
    { value: 'three', label: '三' },
  ];
  const [b, setB] = useState('one');
  const [b, setB] = useState('one');
  const [c, setC] = useState('one');
  const [c, setC] = useState('one');
  return (
    <>
      <CfTabs value={a} onChange={setA} items={items} variant="line" />
      <CfTabs value={b} onChange={setB} items={items} variant="segmented" />
      <CfTabs value={c} onChange={setC} items={items} variant="pill" />
    </>
  );
}

尺寸

3 档尺寸跟随密度系统 --control-h-sm/md/lg

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const sm = ref('one');
const md = ref('one');
const lg = ref('one');
const items = [
  { value: 'one', label: 'Tab 1' },
  { value: 'two', label: 'Tab 2' },
  { value: 'three', label: 'Tab 3' },
];
</script>
<template>
  <div class="demo-stack">
    <CfTabs v-model="sm" :items="items" size="sm" />
    <CfTabs v-model="md" :items="items" size="md" />
    <CfTabs v-model="lg" :items="items" size="lg" />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const sm = ref('one');
const md = ref('one');
const lg = ref('one');
const items = [
  { value: 'one', label: 'Tab 1' },
  { value: 'two', label: 'Tab 2' },
  { value: 'three', label: 'Tab 3' },
];
</script>
<template>
  <div class="demo-stack">
    <CfTabs v-model="sm" :items="items" size="sm" />
    <CfTabs v-model="md" :items="items" size="md" />
    <CfTabs v-model="lg" :items="items" size="lg" />
  </div>
</template>
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const items = [
    { value: 'one', label: 'Tab 1' },
    { value: 'two', label: 'Tab 2' },
    { value: 'three', label: 'Tab 3' },
  ];
  const sm = 'one';
  const md = 'one';
  const lg = 'one';
  return (
    <>
      <CfTabs items={items} size="sm" defaultValue="one" />
      <CfTabs items={items} size="md" defaultValue="one" />
      <CfTabs items={items} size="lg" defaultValue="one" />
    </>
  );
}
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const items = [
    { value: 'one', label: 'Tab 1' },
    { value: 'two', label: 'Tab 2' },
    { value: 'three', label: 'Tab 3' },
  ];
  const sm = 'one';
  const md = 'one';
  const lg = 'one';
  return (
    <>
      <CfTabs items={items} size="sm" defaultValue="one" />
      <CfTabs items={items} size="md" defaultValue="one" />
      <CfTabs items={items} size="lg" defaultValue="one" />
    </>
  );
}

对齐方式

align 控制 tab 列表的水平对齐:start 靠左、center 居中、end 靠右、stretch 等分撑满整行。 对齐方式不影响内容区,只影响 tab 头部。

背景 视口

align = start(默认)

align = center

align = end

align = stretch

src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const items = [
  { value: 'one',   label: '一' },
  { value: 'two',   label: '二' },
  { value: 'three', label: '三' },
];
const a = ref<string>('one');
const b = ref<string>('one');
const c = ref<string>('one');
const d = ref<string>('one');
</script>
<template>
  <div class="demo-stack">
    <div>
      <p class="demo-hint">align = start(默认)</p>
      <CfTabs v-model="a" :items="items" align="start" />
    </div>
    <div>
      <p class="demo-hint">align = center</p>
      <CfTabs v-model="b" :items="items" align="center" />
    </div>
    <div>
      <p class="demo-hint">align = end</p>
      <CfTabs v-model="c" :items="items" align="end" />
    </div>
    <div>
      <p class="demo-hint">align = stretch</p>
      <CfTabs v-model="d" :items="items" align="stretch" />
    </div>
  </div>
</template>
<style scoped>
.demo-hint { margin: 0 0 4px; color: var(--fg-3); font-size: var(--t-12); }
</style>
<script setup>
import { ref } from 'vue';
import { CfTabs } from '@chufix-design/vue';

const items = [
  { value: 'one',   label: '一' },
  { value: 'two',   label: '二' },
  { value: 'three', label: '三' },
];
const a = ref<string>('one');
const b = ref<string>('one');
const c = ref<string>('one');
const d = ref<string>('one');
</script>
<template>
  <div class="demo-stack">
    <div>
      <p class="demo-hint">align = start(默认)</p>
      <CfTabs v-model="a" :items="items" align="start" />
    </div>
    <div>
      <p class="demo-hint">align = center</p>
      <CfTabs v-model="b" :items="items" align="center" />
    </div>
    <div>
      <p class="demo-hint">align = end</p>
      <CfTabs v-model="c" :items="items" align="end" />
    </div>
    <div>
      <p class="demo-hint">align = stretch</p>
      <CfTabs v-model="d" :items="items" align="stretch" />
    </div>
  </div>
</template>
<style scoped>
.demo-hint { margin: 0 0 4px; color: var(--fg-3); font-size: var(--t-12); }
</style>
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('one');
  const [a, setA] = useState('one');
  const items = [
    { value: 'one',   label: '一' },
    { value: 'two',   label: '二' },
    { value: 'three', label: '三' },
  ];
  const [b, setB] = useState('one');
  const [b, setB] = useState('one');
  const [c, setC] = useState('one');
  const [c, setC] = useState('one');
  const [d, setD] = useState('one');
  const [d, setD] = useState('one');
  return (
    <>
      <CfTabs value={a} onChange={setA} items={items} align="start" />
      <CfTabs value={b} onChange={setB} items={items} align="center" />
      <CfTabs value={c} onChange={setC} items={items} align="end" />
      <CfTabs value={d} onChange={setD} items={items} align="stretch" />
    </>
  );
}
import { useState } from 'react';
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const [a, setA] = useState('one');
  const [a, setA] = useState('one');
  const items = [
    { value: 'one',   label: '一' },
    { value: 'two',   label: '二' },
    { value: 'three', label: '三' },
  ];
  const [b, setB] = useState('one');
  const [b, setB] = useState('one');
  const [c, setC] = useState('one');
  const [c, setC] = useState('one');
  const [d, setD] = useState('one');
  const [d, setD] = useState('one');
  return (
    <>
      <CfTabs value={a} onChange={setA} items={items} align="start" />
      <CfTabs value={b} onChange={setB} items={items} align="center" />
      <CfTabs value={c} onChange={setC} items={items} align="end" />
      <CfTabs value={d} onChange={setD} items={items} align="stretch" />
    </>
  );
}

非受控模式

不传 v-model 时组件内部自管 active 状态,默认激活 items[0]。 适合 tab 仅做局部展示切换、外部不需要观察当前激活值的场景。

背景 视口
概览页面 —— 默认激活第一项
src/App.vue
<script setup lang="ts">
import { CfTabs } from '@chufix-design/vue';

const items = [
  { value: 'overview',  label: '概览' },
  { value: 'activity',  label: '动态' },
  { value: 'settings',  label: '设置' },
];
</script>
<template>
  <CfTabs :items="items">
    <template #default="{ active }">
      <div v-if="active === 'overview'">概览页面 —— 默认激活第一项</div>
      <div v-if="active === 'activity'">动态页面</div>
      <div v-if="active === 'settings'">设置页面</div>
    </template>
  </CfTabs>
</template>
<script setup>
import { CfTabs } from '@chufix-design/vue';

const items = [
  { value: 'overview',  label: '概览' },
  { value: 'activity',  label: '动态' },
  { value: 'settings',  label: '设置' },
];
</script>
<template>
  <CfTabs :items="items">
    <template #default="{ active }">
      <div v-if="active === 'overview'">概览页面 —— 默认激活第一项</div>
      <div v-if="active === 'activity'">动态页面</div>
      <div v-if="active === 'settings'">设置页面</div>
    </template>
  </CfTabs>
</template>
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const items = [
    { value: 'overview',  label: '概览' },
    { value: 'activity',  label: '动态' },
    { value: 'settings',  label: '设置' },
  ];
  return (
    <>
      <CfTabs items={items}>
            <div v-if="active === 'overview'">概览页面 —— 默认激活第一项</div>
            <div v-if="active === 'activity'">动态页面</div>
            <div v-if="active === 'settings'">设置页面</div>
    </>
  );
}
import { CfTabs } from '@chufix-design/react';

export default function Demo() {
  const items = [
    { value: 'overview',  label: '概览' },
    { value: 'activity',  label: '动态' },
    { value: 'settings',  label: '设置' },
  ];
  return (
    <>
      <CfTabs items={items}>
            <div v-if="active === 'overview'">概览页面 —— 默认激活第一项</div>
            <div v-if="active === 'activity'">动态页面</div>
            <div v-if="active === 'settings'">设置页面</div>
    </>
  );
}

API

Props · Tabs

Prop类型默认值说明
modelValue (Vue) / value (React)string当前激活 tab 的 value(受控)
defaultValue (React)string初始激活 tab 的 value(非受控;Vue 直接不传 v-model 即可)
itemsTabsItem[][]tab 列表,每项 {value, label, disabled?}
variant'line' | 'segmented' | 'pill''line'视觉变体
size'sm' | 'md' | 'lg''md'高度与字号
align'start' | 'center' | 'end' | 'stretch''start'tab 列表对齐方式

Props · TabPanel

TabPanel 是子组件,当 items prop 未提供时,会从子节点的 props 中自动推断 tab 列表。

Prop类型默认值说明
valuestringpanel 标识,与父 Tabs 的 active 匹配
labelstringtab 头部显示文案;省略时回退到 value
disabledbooleanfalse禁用此 tab(保留视觉,禁止切换)

Events

Vue 事件React 回调载荷类型说明
update:modelValuestringv-model 隐式监听
changeonChangestring切换 active tab 时触发,与 update:modelValue 同步

Slots / Children

SlotProps说明
default{ active: string }tab 内容区;Vue 用 scoped slot,React 用 children: ({ active }) => ReactNode

反馈与讨论

Tabs 标签页 的讨论

0
0 / 600
正在加载评论...