vue-vben-admin 5.8.0 的 shadcn-ui 包:Progress 原语与 progressbar 无障碍语义解析
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
导读
@vben-core/shadcn-ui是 vue-vben-admin Monorepo 中基于 shadcn-vue 风格封装的 UI 组件包,5.8.0 版本为其带来了首个具备标准 progressbar 语义的 Progress 进度条原语。本文将围绕该版本的变更记录,深入解析 Progress 原语的源码实现、ARIA 无障碍语义、非法 max 回退规则与测试用例验证,帮助你理解 shadcn-ui 组件在 vue-vben-admin 内部的封装模式,并掌握在新版本中直接使用进度条组件的方式。
1. 变更记录概览:5.8.0 的 Minor 变更
关联文档 CHANGELOG.md 记录了@vben-core/shadcn-ui5.8.0 的唯一一次 Minor Changes:
feat(@vben-core/shadcn-ui): add Progress primitive with progressbar semantics
该变更由 PR #8305 引入(提交142b544),为组件库新增了带progressbar无障碍语义的 Progress 基础原语。同时,本次版本的 Patch Changes 声明了对同版本号各核心依赖的同步更新:
@vben-core/design@5.8.0@vben-core/icons@5.8.0@vben-core/shared@5.8.0@vben-core/typings@5.8.0@vben-core/composables@5.8.0
从 package.json 可以看到,该包的核心依赖还包括reka-ui(无头 UI 原语库)、class-variance-authority(变体样式)、@vueuse/core、@lucide/vue与vue本身。这意味着 Progress 并非从零实现,而是建立在 reka-ui 的ProgressRoot/ProgressIndicator之上的一层有样式、有语义的封装。
2. shadcn-ui 包在 vue-vben-admin 中的定位
2.1 目录结构与职责划分
@vben-core/shadcn-ui位于 packages/@core/ui-kit/shadcn-ui,其src目录清晰地划分为两层:
src/ui/:对标 shadcn 官方风格的“基础原语层”,按组件逐个目录存放,例如progress/、button/、dialog/、select/等。每个目录通常包含 PascalCase 命名的.vue组件、统一的index.ts导出文件,复杂的原语还附带__tests__/测试目录。src/components/:业务封装层,如table-action、segmented、pin-input、scrollbar等,它们组合多个 ui 原语或第三方能力形成开箱即用的业务组件。src/assets/index.css:样式入口文件,仅一行@reference "@vben/tailwind-config/theme";,通过 Tailwind 的@reference机制引用 internal/tailwind-config/src/theme.css 中的主题设计变量。
入口文件 src/index.ts 同时导出了./components与./ui两层内容,并额外转发 reka-ui 的createContext、Slot、VisuallyHidden三个底层工具,方便外层在组合原语时使用。
2.2 与官方 shadcn-vue 的兼容配置
components.json 沿用了 shadcn-vue 的配置规范,可据此判断该包与官方生态的兼容关系:
{ "$schema": "https://shadcn-vue.com/schema.json", "style": "new-york", "typescript": true, "tailwind": { "config": "", "css": "src/assets/index.css", "baseColor": "slate", "cssVariables": true }, "aliases": { "components": "@vben-core/shadcn-ui/components", "utils": "@vben-core/shared/utils" } }关键点解读:
style为new-york(纽约风格),即组件默认采用较紧凑的现代样式变体;cssVariables为true,样式基于 CSS 变量主题,配合baseColor: slate提供整套语义色板;- 工具函数别名指向
@vben-core/shared/utils(即cn等类名合并工具),而非 shadcn 默认的tailwind-merge独立实现。
3. Progress 原语源码深度解析
3.1 组件结构
Progress 原语由两个文件组成:Progress.vue 与 index.ts,后者仅做单一导出:
export { default as Progress } from './Progress.vue';并在 src/ui/index.ts 中以export * from './progress'随包整体导出,因此业务代码可直接import { Progress } from '@vben-core/shadcn-ui'。
3.2 核心实现
Progress.vue的实现简洁而克制,完整源码如下(已省略部分样式细节):
<script setup lang="ts"> import type { ProgressRootEmits, ProgressRootProps } from 'reka-ui'; import type { HTMLAttributes } from 'vue'; import { computed } from 'vue'; import { cn } from '@vben-core/shared/utils'; import { reactiveOmit } from '@vueuse/core'; import { ProgressIndicator, ProgressRoot, useForwardPropsEmits } from 'reka-ui'; const props = defineProps< ProgressRootProps & { class?: HTMLAttributes['class'] } >(); const emits = defineEmits<ProgressRootEmits>(); /** ProgressRoot 对非法 max 的回退值(max 必须为正数)。 */ const DEFAULT_MAX = 100; const delegatedProps = reactiveOmit(props, 'class'); const forwarded = useForwardPropsEmits(delegatedProps, emits); const normalizedMax = computed(() => { const { max } = props; return typeof max === 'number' && Number.isFinite(max) && max > 0 ? max : DEFAULT_MAX; }); </script> <template> <ProgressRoot v-slot="slotProps" >const normalizedMax = computed(() => { const { max } = props; return typeof max === 'number' && Number.isFinite(max) && max > 0 ? max : DEFAULT_MAX; });归一化后的max同时用于:
- 传入
ProgressRoot的:max属性(保证 ARIA 语义一致); - 指示条
transform的计算分母(保证视觉填充正确)。
这保证了「无障碍属性值」与「实际渲染宽度」在任何边界输入下都保持一致,不会出现语义与视觉分裂。
4. 测试验证:progressbar 语义如何被保证
Progress 原语配套了完整的 Vitest 单测 progress.test.ts,测试通过挂载受控组件、查询[data-slot="progress"]与[data-slot="progress-indicator"]两个钩子来断言行为。测试覆盖的语义契约如下:
| 测试场景 | 输入 | 期望行为 |
|---|---|---|
| 基础进度语义 | modelValue=42, max=100 | role="progressbar",aria-valuemin=0,aria-valuemax=100,aria-valuenow=42 |
| 自定义 max 归一化 | modelValue=30, max=50 | aria-valuemax=50,指示条填充 60%(translateX(-40%)) |
| 非法 max 回退 | max=NaN/Infinity | aria-valuemax=100,填充按 30/100 计算(translateX(-70%)) |
| 不确定状态 | modelValue=null | 省略aria-valuenow,data-state="indeterminate" |
| 零值隐藏 | modelValue=0 | 指示条完全隐藏(translateX(-100%)) |
这些用例直接印证了 5.8.0 CHANGELOG 中 “progressbar semantics” 的具体含义:
- 确定性语义:
role="progressbar"+aria-valuemin/max/now三元组,让屏幕阅读器可以播报精确进度; - 不确定性语义:
modelValue=null时省略aria-valuenow并标记data-state="indeterminate",适用于加载中但无法估算进度的场景; - 边界防御:非法
max一律回退 100,杜绝无穷百分比导致的渲染异常。
5. 使用方式与样式定制
5.1 基础用法
Progress 与原生 HTML 进度条(<progress>)不同,它是完全可控(controlled)组件,进度由modelValue驱动:
<script setup lang="ts"> import { Progress } from '@vben-core/shadcn-ui'; import { ref } from 'vue'; const progress = ref(42); </script> <template> <Progress v-model="progress" /> </template>由于组件透传了 reka-ui 的ProgressRootProps,你可以继续传入 reka-ui 支持的其他属性(如getValueLabel自定义读屏播报文案)。
5.2 自定义 max 与不确定状态
<template> <!-- 自定义总量:30/50 会显示 60% 填充 --> <Progress :model-value="30" :max="50" /> <!-- 不确定状态:不显示具体数值,data-state 为 indeterminate --> <Progress :model-value="null" /> </template>5.3 样式覆盖
两种定制方式:
class透传:内置样式通过cn()与外部类合并,例如class="h-4 rounded-sm"可覆盖默认的h-2 rounded-full尺寸与圆角。- 主题变量:进度条默认使用
bg-primary/20轨道与bg-primary指示条,二者均基于 internal/tailwind-config/src/theme.css 中的primary主题色,因此会跟随项目的深浅色主题与品牌色联动,无需单独维护颜色。
6. 与业务封装层的配合
src/ui/层的原语被上层src/components/业务组件引用。以进度条为参照可以举一反三:基础原语只保证“语义正确 + 基础样式”,复杂交互(如spinner、loading、count-to-animator等业务组件)则在原语之上组合状态逻辑。这种「无头原语(reka-ui)→ 基础 UI 原语(ui/)→ 业务组件(components/)」的三层架构,是整个 shadcn-ui 包的通用模式,也保证了 5.8.0 新增的 Progress 可以直接被后续业务组件安全复用。
7. 版本配套说明
5.8.0 的 Patch Changes 表明,本次发布同时升级了@vben-core/design、@vben-core/icons、@vben-core/shared、@vben-core/typings、@vben-core/composables至同版本号。如果你正在维护基于本仓库的派生项目,升级@vben-core/shadcn-ui时建议连同上述工作区依赖一并同步,以保证类型与样式 token 的一致性;完整的版本演进记录可查阅 CHANGELOG.md。
小结
vue-vben-admin 5.8.0 为@vben-core/shadcn-ui带来的 Progress 原语,是一个「小而完整」的工程范例:它以 reka-ui 的无头能力为底座,用少量代码补齐了样式、类名合并与非法输入防御,并通过单测把progressbar语义固化为可回归验证的契约。理解它的实现与测试,就等于理解了整个 shadcn-ui 包的设计方法论,也让你在新版本中能够安全、无障碍地使用进度条组件。
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考