Gutenberg Components:ProgressBar 进度条组件完全指南
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
ProgressBar 是 Gutenberg(WordPress 区块编辑器项目)组件库@wordpress/components中的一个轻量反馈类组件,用于展示确定或不确定的加载进度。本文基于组件的官方 README 展开,并结合仓库中的源码、样式、测试与 Storybook 示例,完整覆盖其两种模式、全部 Props、默认行为(默认宽度、配色、动画、无障碍处理),以及它在字体库等模块中的真实用法,帮助你在编辑器扩展开发中正确选用和定制这个组件。
组件概览与导出位置
ProgressBar 位于packages/components包内,目录为 packages/components/src/progress-bar,核心文件包括:
| 文件 | 作用 |
|---|---|
| index.tsx | 组件实现(forwardRef封装) |
| types.ts | ProgressBarProps类型定义 |
| style.module.scss | 轨道(track)、指示器(indicator)、原生progress元素的样式 |
| stories/index.story.tsx | Storybook 示例 |
| test/index.browser.test.tsx | 浏览器端行为测试 |
该组件从包入口 packages/components/src/index.ts 导出:
export { default as ProgressBar } from './progress-bar';因此外部代码统一通过命名导入使用:
import { ProgressBar } from '@wordpress/components';两种模式:Determinate 与 Indeterminate
README 给出的核心定义是:ProgressBar 支持两种模式——确定模式(determinate)和不确定模式(indeterminate)。当指定了具体的进度值(0 到 100)时为确定模式;未指定值时则进入不确定模式。
基本用法(不确定模式)
最简用法只需渲染组件本身,即可得到一条持续滑动的加载指示条:
import { ProgressBar } from '@wordpress/components'; const MyLoadingComponent = () => { return <ProgressBar />; };确定模式:传入value
通过value(0 到 100 的数字)表示具体进度百分比:
import { ProgressBar } from '@wordpress/components'; const MyLoadingComponent = ( { progress } ) => { return <ProgressBar value={ progress } />; };自定义外观:className
className会应用到最外层的轨道div上,因此可以在自定义类中覆盖默认宽度等属性。例如让进度条占满父容器:
.my-custom-progress-bar { width: 100%; }import { ProgressBar } from '@wordpress/components'; const MyLoadingComponent = () => { return <ProgressBar className="my-custom-progress-bar" />; };Storybook 中的 WithCustomWidth 示例 演示了同样的技巧:传入className: 'custom-progress-bar',并通过装饰器注入一段width: 100%的 CSS,使进度条拉伸为父元素的全部可用宽度。
Props 全解
组件的 Props 由 types.ts 定义为ProgressBarProps,与 README 的文档完全对应:
| Prop | 类型 | 必填 | 说明 |
|---|---|---|---|
value | number | 否 | 进度值,0 到 100。不指定则进度条视为不确定模式 |
className | string | 否 | 应用到底层进度条轨道(track)div上的 CSS 类 |
继承属性:任何额外传入的 Props 都会透传给底层的<progress/>元素。也就是说,id、aria-label、style等属性都会出现在原生progress元素上——浏览器测试用例专门验证了这一点:传入id="foo-bar-123"、aria-label="in progress..."和style={{ opacity: 0.5 }}后,progressbar角色元素上确实携带了这些属性(见 test/index.browser.test.tsx)。
源码实现解析
阅读 index.tsx 可以看到组件的 DOM 结构是三层:外层轨道div→ 视觉指示器div→ 隐藏的原生<progress>元素。
模式判定逻辑
const { className, value, ...progressProps } = props; const isIndeterminate = ! Number.isFinite( value );判定条件不是简单的“value未传”,而是!Number.isFinite(value):无论是未传、传了NaN还是其他非有限值,组件都会回退到不确定模式。这是一种防御性设计,保证动画状态不会因异常输入而中断。
视觉指示器与 CSS 变量
指示器div通过内联 CSS 变量驱动宽度:
<div className={ clsx( styles.indicator, { [ styles[ 'is-indeterminate' ] ]: isIndeterminate, } ) } style={ { '--indicator-width': ! isIndeterminate ? `${ value }%` : undefined, } } />- 确定模式下,
--indicator-width被设为${value}%,样式表中的width: var(--indicator-width)直接消费该变量; - 不确定模式下,变量交由 SCSS 的
.is-indeterminate规则设置为50%,并叠加一个无限循环的位移动画(见下文样式部分)。
测试用例 test/index.browser.test.tsx 验证了value={55}时计算出的--indicator-width正好是55%;不确定模式下该变量为50%,且指示器宽度等于轨道宽度的一半。
隐藏的语义化<progress>元素
视觉上真正的进度条是那个indicatordiv,但组件还渲染了一个透明的原生<progress>元素:
<progress className={ styles[ 'progress-element' ] } max={ 100 } value={ value } aria-label={ __( 'Loading …' ) } ref={ ref } { ...progressProps } />这个元素承担三个职责:
- 无障碍语义:
<progress>元素天然具备progressbar角色和aria-valuenow等语义,屏幕阅读器可以直接感知进度;默认aria-label通过@wordpress/i18n的__()函数国际化为“Loading …”; forwardRef目标:组件用forwardRef封装,ref 直接落在该元素上,方便父组件操作;- 额外 Props 的落点:README 中“继承属性”一条正是由这里的
{ ...progressProps }展开实现的。
样式上它被opacity: 0隐藏并绝对定位覆盖在轨道之上(见 style.module.scss),因此不影响视觉呈现,也不拦截交互。浏览器测试确认:不确定模式下该元素not.toHaveValue(),确定模式下toHaveValue(55)(test/index.browser.test.tsx)。
样式细节:轨道、动画与无障碍适配
style.module.scss 揭示了几个 README 未展开的默认行为,定制样式前值得了解:
轨道(.track)
- 高度仅
1.5px,是一条纤细的细线; - 背景色为前景色的 10% 不透明度(
color-mix(in srgb, $components-color-foreground, transparent 90%)),随主题前景色自适应深浅色主题; border-radius: 9999px实现全圆角;- 默认宽度:
width: 160px,且写在:where(&)选择器中——:where()的零特异性意味着自定义类(如你传入的className)无需提高优先级即可覆盖默认宽度,这正是className定制方案低摩擦的原因; overflow: hidden保证指示器滑动时不会溢出轨道。
指示器(.indicator)
- 背景色为前景色 90% 不透明度,比轨道更醒目;
- 确定模式下宽度由
--indicator-width变量控制,并在prefers-reduced-motion未开启时对width应用0.4s ease-in-out过渡,让进度变化平滑; - 不确定模式(
.is-indeterminate)下,指示器固定为轨道宽度的 50%,通过indeterminate-slide关键帧动画从-50%滑动到100%,周期 1.5 秒、ease-in-out、无限循环:
@keyframes indeterminate-slide { 0% { inset-inline-start: -$indeterminate-indicator-width; } 100% { inset-inline-start: 100%; } }注意关键帧使用的是inset-inline-start(逻辑属性),因此在 RTL 布局下滑动方向会自动镜像。
减弱动效(prefers-reduced-motion)适配
对于开启系统“减弱动效”的用户,动画降级为更温和的表现:持续时间拉长到 3 秒,并以steps(4, end)分步跳变代替连续滑动。这体现了组件对无障碍偏好的显式尊重。
高对比度模式
轨道与指示器都声明了outline: 2px solid transparent; outline-offset: ...。Windows 高对比度模式下系统会把透明 outline 替换为可见轮廓,从而让这条 1.5px 的细线在强制高对比配色下依然可见。
测试用例验证的行为边界
浏览器端测试 用vitest-browser-react在真实浏览器中渲染组件,覆盖了四类关键行为,可作为你集成该组件时的验收清单:
- 不传
value时,progressbar角色元素存在且无进度值(不确定模式); value={55}时,progressbar元素的值为 55;- 不确定模式下指示器宽度为轨道宽度的一半,
--indicator-width为50%; - 额外 Props(
id、aria-label、style)完整透传到底层progress元素。
测试中的注释还特意说明:轨道与指示器是“刻意不可交互的展示元素”,因此测试通过节点访问而非可访问性选择器来断言它们——这也提示使用方不要把轨道当作可点击或可聚焦的 UI 控件。
仓库内的真实用法
在 Gutenberg 仓库中,ProgressBar 的主要使用方是全局样式编辑器的字体库(font library),用于在字体上传或安装这类耗时操作进行中给出持续加载反馈:
- upload-fonts.tsx:本地字体上传中(
isUploading为真)时,在上传区域渲染一条不确定模式的<ProgressBar />; - installed-fonts.tsx:字体条目列表加载态(第 275 行)以及单个字体安装进行中(
isInstalling时,第 491 行)同样使用该组件; - font-collection.tsx:字体集合页加载态(第 266 行)。
这些用法有一个共性:操作进度无法精确计量时统一采用不确定模式,把确定进度留给需要value的场景。如果你在插件或自定义编辑器界面中需要反馈“耗时操作进行中”,这是仓库内可直接参考的模式。
Storybook 示例与状态标注
Storybook 元数据(stories/index.story.tsx)将该组件标注为status: 'recommended'(推荐使用,非实验性)、whereUsed: 'global'(可用于全站场景),标题路径为Components/Feedback/ProgressBar,id为components-progressbar。它提供了两个 story:
Default:无参数渲染,即不确定模式;WithCustomWidth:演示通过className覆盖默认宽度至100%。
argTypes中将value配置为 0–100、步进 1 的数字控件,方便在 Storybook 面板中直接拖拽验证确定模式的表现。
小结
ProgressBar 是一个 API 面极小但工程细节扎实的反馈组件:两个显式 Prop(value、className)加透传给<progress>的继承属性;模式判定基于Number.isFinite的防御式检查;视觉上由轨道、指示器与隐藏的原生progress三层协同,兼顾主题自适应、RTL、高对比度与减弱动效。集成时只需记住:需要精确进度就传value,其余场景直接<ProgressBar />,宽度定制交给className即可。
【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考