progress —— 进度条
本頁內容尚未翻譯。
进度条表达「某件事完成到多少了」:上传、下载、安装、审核。它是纯展示组件——值驱动一切。core/progress 管的是百分比钳制、状态推导(满额自动 success)、圆形进度的周长换算、以及 APG progressbar 语义。
- 各端实现
LhProgress:文件上传进度、任务执行进度、加载耗时提示、容量占用。 - 有明确「当前值 / 总量」比例的场景。
- 不该用它:无确定进度的加载(用
spinner/loading,它们表达「在转」而非「到哪了」);步骤导航(用steps)。
import { clampPercent, resolveStatus, getProgressClassNames, getCircleCircumference, getProgressColor, formatPercentText, getProgressAria,} from '@lh-ui/share/core/progress'import type { LhProgressType, LhProgressStatus, LhProgressState } from '@lh-ui/share/core/progress'resolveStatus 的自动推导:status 为默认的 'normal' 时,value >= 100 自动变 'success'。这是「约定优于配置」——满了就是成功了,用户不必每个进度条都写 :status="value >= 100 ? 'success' : 'normal'"。但显式指定的状态不被覆盖:传了 warning 就一直是 warning,即使 100%。
clampPercent 的 NaN 归零:NaN 返回 0 而非传播。进度值常来自异步计算(loaded / total,total 为 0 时是 NaN),归零让 UI 显示「0%」而非崩溃或显示 NaN%。
圆形周长的换算:getCircleCircumference(width, strokeWidth) = 2π × (width - strokeWidth) / 2。这是 SVG stroke-dasharray 的标准算法:stroke-dasharray = 周长、stroke-dashoffset = 周长 × (1 - percent/100)。半径要先减去描边宽度的一半,否则圆会比画布大一圈。
getProgressColor 的三级优先:用户传入的 color(函数或字符串)> 状态对应 token > 默认主色。函数形式((percentage) => string)支持渐变进度条(如 0-50 绿色、50-80 黄色、80+ 红色)。
| 函数 | 签名 | 返回 | 作用 |
|---|---|---|---|
clampPercent |
(value: number) => number |
[0,100] | NaN 归零 |
resolveStatus |
(value, status) => LhProgressStatus |
状态 | normal 且 ≥100 → success |
getProgressClassNames |
(state: LhProgressState) => string[] |
类名 | 类型/状态/文字 |
getCircleCircumference |
(width, strokeWidth) => number |
周长 | SVG dash 计算 |
getProgressColor |
(status, color?, percentage?) => string |
颜色 | 三级优先 |
formatPercentText |
(percentage) => string |
'50%' |
取整文案 |
getProgressAria |
(options: { percentage, label? }) => LhAriaAttrs |
aria 属性包 | progressbar 语义 |
export type LhProgressType = 'line' | 'circle'export type LhProgressStatus = 'normal' | 'success' | 'warning' | 'exception'
export interface LhProgressState { type: LhProgressType status: LhProgressStatus showText: boolean strokeWidth: number // line 为高度 px,circle 为 SVG stroke 宽度 width: number // 圆形画布宽度 px}getProgressAria({ percentage: 60, label: '上传进度' })// { role: 'progressbar', 'aria-valuenow': 60, 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-label': '上传进度' }
getProgressAria({ percentage: 100 })// { role: 'progressbar', 'aria-valuenow': 100, 'aria-valuemin': 0, 'aria-valuemax': 100 }role="progressbar"是 APG 的标准角色,读屏软件播报「进度条 60%」。aria-label在无可见文字时必需:showText: false的进度条对读屏用户完全不可见,必须有可达名称。有可见文字时可以省略(文字本身就是名称)。- 进度条是
aria-readonly的(默认隐含),不需要额外声明。 - 动态进度的播报节流:每秒更新几十次的进度条,
aria-valuenow频繁变化会让读屏软件刷屏。UI 层更新aria-valuenow的频率应降到约每秒一次(视觉动画不受影响,只降 aria 更新频率)。
import { clampPercent, resolveStatus, getProgressColor, getCircleCircumference } from '@lh-ui/share/core/progress'
clampPercent(50) // 50clampPercent(150) // 100clampPercent(-10) // 0clampPercent(NaN) // 0
resolveStatus(100, 'normal') // 'success'(满额自动)resolveStatus(100, 'warning') // 'warning'(显式状态不覆盖)resolveStatus(50, 'normal') // 'normal'
getProgressColor('normal') // 'var(--lh-primary-color)'getProgressColor('success') // 'var(--lh-success-color)'getProgressColor('warning') // 'var(--lh-warning-color)'getProgressColor('exception') // 'var(--lh-danger-color)'getProgressColor('normal', '#f00') // '#f00'(字符串优先)getProgressColor('normal', (p) => p > 80 ? 'var(--lh-danger-color)' : 'var(--lh-success-color)', 90)// 'var(--lh-danger-color)'(函数按当前百分比取色)
getCircleCircumference(120, 8) // 2π × 56 ≈ 351.86formatPercentText(49.6) // '50%'(取整)// 渐变色配置(函数 color)const color = (percentage: number) => percentage < 30 ? 'var(--lh-success-color)' : percentage < 70 ? 'var(--lh-warning-color)' : 'var(--lh-danger-color)'<!-- Vue3:线性 --><div :class="getProgressClassNames({ type: 'line', status, showText, strokeWidth, width })"> <div class="lh-progress__bar" role="progressbar" :aria-valuenow="clamped" aria-valuemin="0" aria-valuemax="100" :aria-label="showText ? undefined : label" > <div class="lh-progress__fill" :style="{ width: clamped + '%', height: strokeWidth + 'px', background: barColor }" /> </div> <span v-if="showText" class="lh-progress__text">{{ formatPercentText(clamped) }}</span></div><!-- Vue3:圆形 --><div :class="getProgressClassNames({ type: 'circle', status, showText, strokeWidth, width })"> <svg :width="width" :height="width" :viewBox="`0 0 ${width} ${width}`"> <circle :cx="width / 2" :cy="width / 2" :r="(width - strokeWidth) / 2" :stroke-width="strokeWidth" fill="none" class="lh-progress__circle-track" /> <circle :cx="width / 2" :cy="width / 2" :r="(width - strokeWidth) / 2" :stroke-width="strokeWidth" fill="none" :stroke="barColor" stroke-linecap="round" :stroke-dasharray="circumference" :stroke-dashoffset="circumference * (1 - clamped / 100)" :transform="`rotate(-90 ${width / 2} ${width / 2})`" /> </svg> <span v-if="showText" class="lh-progress__circle-text">{{ formatPercentText(clamped) }}</span></div>const clamped = computed(() => clampPercent(props.percentage))const status = computed(() => resolveStatus(clamped.value, props.status))const barColor = computed(() => getProgressColor(status.value, props.color, clamped.value))const circumference = computed(() => getCircleCircumference(props.width, props.strokeWidth))// React:圆形用 stroke-dashoffset 动画(CSS transition 在该属性上)// uniapp:线性用 <view> 宽度百分比;圆形需 <canvas> 或 SVG(部分端支持有限),// 简化方案是用线性进度条替代圆形| 类名 | 语义 |
|---|---|
.lh-progress / --line / --circle |
基础类 / 类型 |
.lh-progress--success / --warning / --exception |
状态(文字色 + 填充色) |
.lh-progress--no-text |
无文字(去掉右侧文字槽位) |
.lh-progress__bar |
轨道 |
.lh-progress__fill |
填充(宽度百分比) |
.lh-progress__text |
线性文字 |
.lh-progress__circle-track |
圆形轨道 |
.lh-progress__circle-text |
圆形中心文字 |
轨道色 --lh-fill-color,填充默认 --lh-primary-color,状态色取 --lh-success-color / --lh-warning-color / --lh-danger-color。
strokeWidth的双重含义:line 模式下是填充的高度(px),circle 模式下是 SVG 的描边宽度。同一个 prop 两种语义,UI 层按type分别消费。- 圆形的
width与strokeWidth关系:strokeWidth不能大于width,否则半径为负,周长算出负数,stroke-dashoffset行为未定义。 showText: false时必须给aria-label——这是无障碍的硬性要求,不是可选项。- 动画的边界:填充宽度从 0 跳到 80% 时 CSS transition 会补间动画;但
clamped从 NaN 归零的瞬间会闪一下,UI 层可在值稳定前不渲染。 resolveStatus与 UI 层状态联动:如果业务希望「100% 但仍在处理中」保持 normal,显式传status="normal"会被自动覆盖(因为自动推导只在 normal 时触发,且 normal → success 是单向的)——此时改用exception或自定义颜色绕开。- 百分比大于 100 的业务语义:
clampPercent直接钳到 100。若业务要表达「超额完成」(如 120%),不要用 progress,用statistic展示数字。 formatPercentText取整:49.6显示50%,丢失精度;需要小数的业务自行格式化(core 不提供参数,保持函数最小)。
@lh-ui/share/core/progress → getProgressColor( )(填好参数后点运行)Copyright © 2024-2026 风默文学 | 宁ICP备2024006574号 |
苏公网安备32040002010537