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

List 列表

通用列表,支持选中(单选 / 多选)、分组、卡片化、自定义渲染。

单选

selectable="single" 把列表变成单选控件,v-model 绑定 string

背景 视口
  • Alice Chen前端工程师 · 上海
  • Bob Wang后端工程师 · 北京
  • Carol Liu设计师 · 深圳
  • Dave Zhang产品经理 · 杭州
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfList, type ListItem } from '@chufix-design/vue';

const value = ref<string | string[] | null>('alice');
const items: ListItem[] = [
  { key: 'alice', label: 'Alice Chen', description: '前端工程师 · 上海' },
  { key: 'bob', label: 'Bob Wang', description: '后端工程师 · 北京' },
  { key: 'carol', label: 'Carol Liu', description: '设计师 · 深圳', disabled: true },
  { key: 'dave', label: 'Dave Zhang', description: '产品经理 · 杭州' },
];
</script>
<template>
  <CfList
    v-model="value"
    selectable="single"
    :items="items"
  />
</template>
<script setup>
import { ref } from 'vue';
import { CfList } from '@chufix-design/vue';

const value = ref<string | string[] | null>('alice');
const items= [
  { key: 'alice', label: 'Alice Chen', description: '前端工程师 · 上海' },
  { key: 'bob', label: 'Bob Wang', description: '后端工程师 · 北京' },
  { key: 'carol', label: 'Carol Liu', description: '设计师 · 深圳', disabled: true },
  { key: 'dave', label: 'Dave Zhang', description: '产品经理 · 杭州' },
];
</script>
<template>
  <CfList
    v-model="value"
    selectable="single"
    :items="items"
  />
</template>
import { useState } from 'react';
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const [value, setValue] = useState<string | string[] | null>('alice');
  const items: ListItem[] = [
    { key: 'alice', label: 'Alice Chen', description: '前端工程师 · 上海' },
    { key: 'bob', label: 'Bob Wang', description: '后端工程师 · 北京' },
    { key: 'carol', label: 'Carol Liu', description: '设计师 · 深圳', disabled: true },
    { key: 'dave', label: 'Dave Zhang', description: '产品经理 · 杭州' },
  ];
  return (
    <>
      <CfList value={value} onChange={setValue} selectable="single" items={items} />
    </>
  );
}
import { useState } from 'react';
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const [value, setValue] = useState<string | string[] | null>('alice');
  const items= [
    { key: 'alice', label: 'Alice Chen', description: '前端工程师 · 上海' },
    { key: 'bob', label: 'Bob Wang', description: '后端工程师 · 北京' },
    { key: 'carol', label: 'Carol Liu', description: '设计师 · 深圳', disabled: true },
    { key: 'dave', label: 'Dave Zhang', description: '产品经理 · 杭州' },
  ];
  return (
    <>
      <CfList value={value} onChange={setValue} selectable="single" items={items} />
    </>
  );
}

多选 + 分组

每个 ListItem 可声明 group,相同 group 会自动聚合到一起,并显示分组标题。selectable="multiple"v-model 绑定 string[]

背景 视口
工程
  • Alice
  • Bob
设计
  • Carol
  • Dave
产品
  • Eve
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfList, type ListItem } from '@chufix-design/vue';

const value = ref<string[]>(['alice', 'eve']);
const items: ListItem[] = [
  { key: 'alice', label: 'Alice', group: '工程' },
  { key: 'bob', label: 'Bob', group: '工程' },
  { key: 'carol', label: 'Carol', group: '设计' },
  { key: 'dave', label: 'Dave', group: '设计' },
  { key: 'eve', label: 'Eve', group: '产品' },
];
</script>
<template>
  <CfList
    v-model="value"
    selectable="multiple"
    :items="items"
    variant="default"
  />
</template>
<script setup>
import { ref } from 'vue';
import { CfList } from '@chufix-design/vue';

const value = ref<string[]>(['alice', 'eve']);
const items= [
  { key: 'alice', label: 'Alice', group: '工程' },
  { key: 'bob', label: 'Bob', group: '工程' },
  { key: 'carol', label: 'Carol', group: '设计' },
  { key: 'dave', label: 'Dave', group: '设计' },
  { key: 'eve', label: 'Eve', group: '产品' },
];
</script>
<template>
  <CfList
    v-model="value"
    selectable="multiple"
    :items="items"
    variant="default"
  />
</template>
import { useState } from 'react';
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const [value, setValue] = useState<string[]>(['alice', 'eve']);
  const items: ListItem[] = [
    { key: 'alice', label: 'Alice', group: '工程' },
    { key: 'bob', label: 'Bob', group: '工程' },
    { key: 'carol', label: 'Carol', group: '设计' },
    { key: 'dave', label: 'Dave', group: '设计' },
    { key: 'eve', label: 'Eve', group: '产品' },
  ];
  return (
    <>
      <CfList value={value} onChange={setValue} selectable="multiple" items={items} variant="default" />
    </>
  );
}
import { useState } from 'react';
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const [value, setValue] = useState<string[]>(['alice', 'eve']);
  const items= [
    { key: 'alice', label: 'Alice', group: '工程' },
    { key: 'bob', label: 'Bob', group: '工程' },
    { key: 'carol', label: 'Carol', group: '设计' },
    { key: 'dave', label: 'Dave', group: '设计' },
    { key: 'eve', label: 'Eve', group: '产品' },
  ];
  return (
    <>
      <CfList value={value} onChange={setValue} selectable="multiple" items={items} variant="default" />
    </>
  );
}

三种 variant

variant 控制视觉层次 —— default(紧凑,无分割线)/ divided(行间细分割线)/ card(每项独立卡片,自带间距)。

背景 视口
default —— 紧凑,行间无分割线
  • Alice Chen前端工程师
  • Bob Wang后端工程师
  • Carol Liu设计师
divided —— 行间细分割线
  • Alice Chen前端工程师
  • Bob Wang后端工程师
  • Carol Liu设计师
card —— 每项独立卡片
  • Alice Chen前端工程师
  • Bob Wang后端工程师
  • Carol Liu设计师
src/App.vue
<script setup lang="ts">
import { CfList, type ListItem } from '@chufix-design/vue';

const items: ListItem[] = [
  { key: 'a', label: 'Alice Chen', description: '前端工程师' },
  { key: 'b', label: 'Bob Wang',   description: '后端工程师' },
  { key: 'c', label: 'Carol Liu',  description: '设计师' },
];
</script>
<template>
  <div class="demo-stack">
    <div>
      <span class="adm-label">default —— 紧凑,行间无分割线</span>
      <CfList variant="default" :items="items" />
    </div>
    <div>
      <span class="adm-label">divided —— 行间细分割线</span>
      <CfList variant="divided" :items="items" />
    </div>
    <div>
      <span class="adm-label">card —— 每项独立卡片</span>
      <CfList variant="card" :bordered="false" :items="items" />
    </div>
  </div>
</template>
<style scoped>
.demo-stack { display: flex; flex-direction: column; gap: 18px; }
.adm-label { display: block; color: var(--fg-3); font-size: var(--t-12); margin-bottom: 6px; }
</style>
<script setup>
import { CfList } from '@chufix-design/vue';

const items= [
  { key: 'a', label: 'Alice Chen', description: '前端工程师' },
  { key: 'b', label: 'Bob Wang',   description: '后端工程师' },
  { key: 'c', label: 'Carol Liu',  description: '设计师' },
];
</script>
<template>
  <div class="demo-stack">
    <div>
      <span class="adm-label">default —— 紧凑,行间无分割线</span>
      <CfList variant="default" :items="items" />
    </div>
    <div>
      <span class="adm-label">divided —— 行间细分割线</span>
      <CfList variant="divided" :items="items" />
    </div>
    <div>
      <span class="adm-label">card —— 每项独立卡片</span>
      <CfList variant="card" :bordered="false" :items="items" />
    </div>
  </div>
</template>
<style scoped>
.demo-stack { display: flex; flex-direction: column; gap: 18px; }
.adm-label { display: block; color: var(--fg-3); font-size: var(--t-12); margin-bottom: 6px; }
</style>
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items: ListItem[] = [
    { key: 'a', label: 'Alice Chen', description: '前端工程师' },
    { key: 'b', label: 'Bob Wang',   description: '后端工程师' },
    { key: 'c', label: 'Carol Liu',  description: '设计师' },
  ];
  return (
    <>
      <div className="demo-stack">
          <div>
            <span className="adm-label">default —— 紧凑,行间无分割线</span>
            <CfList variant="default" items={items} />
          </div>
          <div>
            <span className="adm-label">divided —— 行间细分割线</span>
            <CfList variant="divided" items={items} />
          </div>
          <div>
            <span className="adm-label">card —— 每项独立卡片</span>
            <CfList variant="card" bordered={false} items={items} />
          </div>
        </div>
    </>
  );
}
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items= [
    { key: 'a', label: 'Alice Chen', description: '前端工程师' },
    { key: 'b', label: 'Bob Wang',   description: '后端工程师' },
    { key: 'c', label: 'Carol Liu',  description: '设计师' },
  ];
  return (
    <>
      <div className="demo-stack">
          <div>
            <span className="adm-label">default —— 紧凑,行间无分割线</span>
            <CfList variant="default" items={items} />
          </div>
          <div>
            <span className="adm-label">divided —— 行间细分割线</span>
            <CfList variant="divided" items={items} />
          </div>
          <div>
            <span className="adm-label">card —— 每项独立卡片</span>
            <CfList variant="card" bordered={false} items={items} />
          </div>
        </div>
    </>
  );
}

三档尺寸

size 控制行高与字号 —— sm 适合长列表 / 紧凑后台、md 默认、lg 适合触摸友好的场景。

背景 视口
sm
  • Alice Chen前端工程师 · 上海
  • Bob Wang后端工程师 · 北京
  • Carol Liu设计师 · 深圳
md
  • Alice Chen前端工程师 · 上海
  • Bob Wang后端工程师 · 北京
  • Carol Liu设计师 · 深圳
lg
  • Alice Chen前端工程师 · 上海
  • Bob Wang后端工程师 · 北京
  • Carol Liu设计师 · 深圳
src/App.vue
<script setup lang="ts">
import { CfList, type ListItem } from '@chufix-design/vue';

const items: ListItem[] = [
  { key: 'a', label: 'Alice Chen', description: '前端工程师 · 上海' },
  { key: 'b', label: 'Bob Wang',   description: '后端工程师 · 北京' },
  { key: 'c', label: 'Carol Liu',  description: '设计师 · 深圳' },
];
</script>
<template>
  <div class="demo-stack">
    <div><span class="adm-label">sm</span><CfList size="sm" :items="items" /></div>
    <div><span class="adm-label">md</span><CfList size="md" :items="items" /></div>
    <div><span class="adm-label">lg</span><CfList size="lg" :items="items" /></div>
  </div>
</template>
<style scoped>
.demo-stack { display: flex; flex-direction: column; gap: 14px; }
.adm-label { display: block; color: var(--fg-3); font-size: var(--t-12); margin-bottom: 6px; font-family: var(--font-mono); }
</style>
<script setup>
import { CfList } from '@chufix-design/vue';

const items= [
  { key: 'a', label: 'Alice Chen', description: '前端工程师 · 上海' },
  { key: 'b', label: 'Bob Wang',   description: '后端工程师 · 北京' },
  { key: 'c', label: 'Carol Liu',  description: '设计师 · 深圳' },
];
</script>
<template>
  <div class="demo-stack">
    <div><span class="adm-label">sm</span><CfList size="sm" :items="items" /></div>
    <div><span class="adm-label">md</span><CfList size="md" :items="items" /></div>
    <div><span class="adm-label">lg</span><CfList size="lg" :items="items" /></div>
  </div>
</template>
<style scoped>
.demo-stack { display: flex; flex-direction: column; gap: 14px; }
.adm-label { display: block; color: var(--fg-3); font-size: var(--t-12); margin-bottom: 6px; font-family: var(--font-mono); }
</style>
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items: ListItem[] = [
    { key: 'a', label: 'Alice Chen', description: '前端工程师 · 上海' },
    { key: 'b', label: 'Bob Wang',   description: '后端工程师 · 北京' },
    { key: 'c', label: 'Carol Liu',  description: '设计师 · 深圳' },
  ];
  return (
    <>
      <div className="demo-stack">
          <div><span className="adm-label">sm</span><CfList size="sm" items={items} /></div>
          <div><span className="adm-label">md</span><CfList size="md" items={items} /></div>
          <div><span className="adm-label">lg</span><CfList size="lg" items={items} /></div>
        </div>
    </>
  );
}
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items= [
    { key: 'a', label: 'Alice Chen', description: '前端工程师 · 上海' },
    { key: 'b', label: 'Bob Wang',   description: '后端工程师 · 北京' },
    { key: 'c', label: 'Carol Liu',  description: '设计师 · 深圳' },
  ];
  return (
    <>
      <div className="demo-stack">
          <div><span className="adm-label">sm</span><CfList size="sm" items={items} /></div>
          <div><span className="adm-label">md</span><CfList size="md" items={items} /></div>
          <div><span className="adm-label">lg</span><CfList size="lg" items={items} /></div>
        </div>
    </>
  );
}

卡片化

variant="card" 把每一项渲染成独立卡片,自带间距与圆角,适合展示订单 / 通知等独立条目。

背景 视口
  • 订单 #2026-001总额 ¥1,280 · 已支付
  • 订单 #2026-002总额 ¥698 · 已发货
  • 订单 #2026-003总额 ¥3,450 · 处理中
src/App.vue
<script setup lang="ts">
import { CfList, type ListItem } from '@chufix-design/vue';

const items: ListItem[] = [
  { key: '1', label: '订单 #2026-001', description: '总额 ¥1,280 · 已支付' },
  { key: '2', label: '订单 #2026-002', description: '总额 ¥698 · 已发货' },
  { key: '3', label: '订单 #2026-003', description: '总额 ¥3,450 · 处理中' },
];
</script>
<template>
  <CfList :items="items" variant="card" :bordered="false" />
</template>
<script setup>
import { CfList } from '@chufix-design/vue';

const items= [
  { key: '1', label: '订单 #2026-001', description: '总额 ¥1,280 · 已支付' },
  { key: '2', label: '订单 #2026-002', description: '总额 ¥698 · 已发货' },
  { key: '3', label: '订单 #2026-003', description: '总额 ¥3,450 · 处理中' },
];
</script>
<template>
  <CfList :items="items" variant="card" :bordered="false" />
</template>
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items: ListItem[] = [
    { key: '1', label: '订单 #2026-001', description: '总额 ¥1,280 · 已支付' },
    { key: '2', label: '订单 #2026-002', description: '总额 ¥698 · 已发货' },
    { key: '3', label: '订单 #2026-003', description: '总额 ¥3,450 · 处理中' },
  ];
  return (
    <>
      <CfList items={items} variant="card" bordered={false} />
    </>
  );
}
import { CfList } from '@chufix-design/react';

export default function Demo() {
  const items= [
    { key: '1', label: '订单 #2026-001', description: '总额 ¥1,280 · 已支付' },
    { key: '2', label: '订单 #2026-002', description: '总额 ¥698 · 已发货' },
    { key: '3', label: '订单 #2026-003', description: '总额 ¥3,450 · 处理中' },
  ];
  return (
    <>
      <CfList items={items} variant="card" bordered={false} />
    </>
  );
}

API

Props

属性类型默认值说明
itemsListItem[][]数据数组
modelValue (Vue) / value (React)string | string[] | nullnull选中项;类型由 selectable 决定
selectable'single' | 'multiple' | undefined选择模式;省略则无选择行为
size'sm' | 'md' | 'lg''md'尺寸
variant'default' | 'divided' | 'card''default'视觉模式
borderedbooleantrue整体描边
hoverablebooleantrue鼠标悬停高亮
emptyTextstring | ReactNode'暂无数据'空状态文案

ListItem

interface ListItem {
  key: string;
  label?: string;
  description?: string;
  leading?: string;   // 原始 SVG 字符串,通过 v-html 注入
  trailing?: string;  // 原始 SVG 字符串
  disabled?: boolean;
  group?: string;     // 分组 key,相同 group 自动聚合
  [extra: string]: unknown;
}

Events

Vue 事件React 回调载荷类型说明
update:modelValueonChangestring | string[] | null选中项变化时触发,类型与 modelValue 保持一致
selectonSelectListItem点击单项时触发(包括非 selectable 模式),载荷是被点击的原始 item 对象

Slots

Slot作用域参数说明
default{ item: ListItem, selected: boolean }完全自定义每行渲染(React 端:renderItem={(item, selected) => ...}
empty自定义空状态(React 端:传 ReactNode 给 emptyText

反馈与讨论

List 列表 的讨论

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