FilterChips 筛选胶囊
带圆点与计数的单选筛选条,可作为工具栏或标签页语义使用。
FilterChips 筛选胶囊
基础用法
FilterChips
状态筛选
计数由真实数据推导,不是写死的字面量。
示例加载中...
与表格组合
筛选条只负责「选了哪一项」,过滤本身由宿主完成——这样计数、行数据与表格永远是同一份真相。
筛选 + 数据表格
计数从行数据推导;日期列按时间戳排序,而不是按渲染出来的月份文本。
示例加载中...
API
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | string | number | - | 当前选中的 chip |
items | FilterChipItem[] | [] | chip 列表 |
disabled | boolean | false | 禁用整条筛选条 |
role | 'toolbar' | 'tablist' | 'toolbar' | ARIA 语义,见「交互契约」 |
indicator | boolean | true | 选中底色作为一个滑块在 chip 之间平移;关掉则退回逐 chip 上色 |
iconOnly | boolean | false | 只画 iconClass,label 转到 aria-label 与 title;没有图标的 chip 仍显示文字 |
ariaLabel | string | 'Filters' | 筛选条的可访问名 |
FilterChipItem
| 字段 | 类型 | 说明 |
|---|---|---|
value | string | number | chip 唯一标识 |
label | string | chip 文案 |
iconClass | string | 前置图标 class,画在圆点与文案之前;不传则不渲染 |
dot | string | 前置圆点颜色;不传则不渲染圆点 |
count | number | 尾部计数徽标;不传则不渲染。应当从数据推导 |
disabled | boolean | 单独禁用该 chip |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
update:modelValue | (value) | 选中变化 |
change | (value) | 选中变化(与上一条同时触发) |
Slots
| 名称 | 说明 |
|---|---|
chip | 替换 chip 内部内容;接收 { item, active }。按钮外壳与键盘行为仍由组件保留 |
交互契约
- 整条筛选条只有一个 Tab 停靠点:焦点落在选中的 chip 上(没有选中项时落在第一个可用 chip),方向键在 chip 之间移动。
- 方向键会绕回,并跳过禁用的 chip;
Home/End直达首尾。 role="toolbar"(默认)时 chip 是aria-pressed开关,移动焦点不会改变筛选,需要显式激活。role="tablist"时 chip 变成role="tab"+aria-selected,选中跟随焦点;此时宿主应当同时渲染对应的role="tabpanel"区域。- 点击已选中的 chip 不会重复触发事件。
indicator(默认开)把选中底色画成一个元素并让它平移到新 chip;静止观感与关掉时逐像素一致,区别只在两态之间。关掉后底色回到每个 chip 自己身上。- 该滑块是滚动行的绝对定位子元素,因此随 chip 一起横向滚动——它测的是 chip 的
offsetLeft/offsetTop,不是视口坐标。 - 不该被「看见移动」的位置不会做补间:首帧、chip 列表被重建(宿主重新拉取选项)、以及尺寸变化(含 webfont 落地后 chip 变宽)都是直接落位。
- 没有任何选中项时不画滑块,而不是让它停在第 0 个 chip 上。
iconOnly下每个 chip 收成 30px 方块(pill 的内边距是为文字留的,单个图标放进去会漂在椭圆里),label转到aria-label与title,辅助技术与 hover 仍能读到名字。没有iconClass的 chip 不受影响,照常显示文字——空 chip 比啰嗦的 chip 更糟。prefers-reduced-motion: reduce下滑块不做补间,直接落位。- 「不补间」的守卫要等新盒子写入 DOM 之后的下一帧才解除。在同一帧解除会让
width从 0 补间上来,首帧画出 0 宽——这个顺序错误发布过一次,现由filter-chips.test.ts钉住。 - 计数由宿主传入,组件看不到数据,也不会自行推导。
最佳实践
- 计数一律用
computed从行数据算出来。写死字面量的那一刻它就开始说谎——新增一行就对不上了。 - 筛选逻辑放宿主:chip 只表达「选了哪一项」,被过滤掉的行应当真正从数据里移除,而不是靠 CSS 藏起来(藏起来的行仍在无障碍树和 Tab 序列里)。
- 单纯的列表筛选保持默认
role="toolbar";只有确实存在成组的互斥面板时才用tablist。 - 圆点是辅助信息,不要让颜色成为状态的唯一载体——
label必须自己说清楚。 - chip 多于两三个时给每个都配
iconClass:只有文字的一排 chip 会连成一句话,图标是每个 chip 的起始边界。图标是装饰性的(aria-hidden),命名仍然由label承担。 - 图标本身就能认出来时(星标、品牌标)再开
iconOnly;图标只是抽象的类别符号时留着文字,hover 才看到名字的 chip 不算能认。 - 只有当 chip 会在宿主自己的动效期间被整体重排时才关
indicator:两套位移叠在一起会互相打架。单纯不想要动效不必关它——系统的「减弱动态效果」已经会把补间切掉。
Source
- Component source:
packages/tuffex/packages/components/src/filter-chips/src/TxFilterChips.vue。 - Types:
packages/tuffex/packages/components/src/filter-chips/src/types.ts导出FilterChipsProps、FilterChipItem、FilterChipsRole、FilterChipValue、FilterChipsEmits。 - 实测覆盖:
packages/tuffex/packages/components/src/filter-chips/__tests__/filter-chips.test.ts共 15 例,覆盖 chip / 圆点 / 计数渲染、toolbar 与 tablist 两套 ARIA、v-model 与 change 发射、重复点击不发事件、roving tabindex 与无选中时的回退、方向键绕回与跳过禁用项、tablist 下选中跟随焦点、禁用态、chip 插槽与选中滑块;filter-chips-motion.test.ts另有 3 例编译样式契约。
查看源码
packages/tuffex/packages/components/src/filter-chips/index.ts