返回博客

在 Storybook 中构建页面

为难以触达的页面状态编写故事

loading
Kyle Gach
@kylegach
最后更新

在应用中构建页面起初可能看起来很简单,但随着项目日趋成熟,事情会变得更加复杂。如果网络失败或数据丢失怎么办?更糟的是,如果你的应用收到了格式错误或不完整的数据怎么办?在所有这些情况下,页面应该如何渲染?

Mozilla、The Guardian 和 Shopify 的领导团队使用 Storybook 来捕获难以重现的页面状态。这有助于他们有条不紊地解决用户可能遇到的每种情况。

本文将展示如何使用 Storybook 隔离开发页面。我们将使用组件百科全书来演示这个过程——这是一个新网站,它收录了全世界的 UI 组件供前端开发者参考。它包含数百个页面,需要考虑各种 UI 状态和数据差异。

Three examples of the Project Detail page, for Adobe Spectrum Design System, Monday.com Vibe Design System, and The Guardian Web
每个页面根据可用数据进行定制

为何将 Storybook 用于页面?

页面具有不明显的非功能性需求,如布局、可访问性、设备兼容性、性能和用户个性化。这给前端开发者带来了无数需要构建和维护的状态。

Storybook 帮助你隔离构建每种页面状态,然后将其保存为一个故事,以便在 QA 和自动化测试期间重新访问。

💎 捕获边缘情况
故事展示了页面的各种状态。这包括在你的应用中难以触达的边缘情况,如加载状态和空状态。

🖼 分享你的工作
通过发布你的 Storybook,你可以与团队共享处于特定状态的某个故事的链接以获取反馈。这简化了批准流程。

✅ 测试用户交互
即使是最基本的任务也需要用户在页面上跨多个组件完成一系列步骤。你可以通过编写用户行为脚本并在 play 函数中编写断言来验证此类交互。

如何在 Storybook 中构建页面

页面本质上只是一个具有额外数据需求的组件。你以类似于常规组件的方式构建它。首先开发页面在所有数据都存在的最常见“默认”状态。然后为边缘情况编写故事,例如没有数据、数据丢失、响应式断点等。

故事帮助你跟踪页面状态

页面的理想状态是提供所有数据。我们可以编写一个 Default 故事,用输入捕获此状态

Default.args = {
 authorAvatarUrl: mockImageUrl(50, 50),
 componentCount: 55,
 components: mockComponents,
 contributors: [
   {
     avatarUrl: mockImageUrl(50, 50),
     name: 'First Last',
   },
   {
     avatarUrl: mockImageUrl(50, 50),
     name: 'First Last',
   },
   {
     avatarUrl: mockImageUrl(50, 50),
     name: 'First Last',
   },
 ],
 description: 'Spectrum provides components and tools to help product teams work more efficiently, and to make Adobes applications more cohesive',
 downloads: 15123,
 gitHubUrl: '#',
 org: 'Adobe',
 packageName: 'packagename',
 storyCount: 135,
 storybookUrl: '#',
 title: 'Spectrum Design System',
}
The Project Detail page for Adobe Spectrum Design System, in its ideal state, rendered as a story in Storybook

但那些不太理想的情况呢,比如“没有数据”的状态?我们可以重用 Default 故事的输入,然后覆盖一些值来正确创建该状态

NoComponents.args = {
 ...Default.args,
 componentCount: 0,
 components: []
}
The Project Detail page in a story for the "no components" state

有时,页面的状态需要通过与之交互来演示,而不是通过提供输入。我们可以使用play 函数来模拟交互,例如在过滤控件中输入以检查其行为和结果

Filter.args = {
 ...Default.args
};
Filter.play = async ({ canvasElement }) => {
 const canvas = within(canvasElement);
 const filter = await canvas.findByLabelText('Filter by name');
 
 await userEvent.type(filter, 'But', { delay: 100 });
};
An animation of a story demonstrating the "components filter" functionality
使用交互测试模拟用户行为

将复杂页面分解为简单组件

如果你采用组件驱动的方法,即 UI 由可重用组件组装而成,你可以进一步分解页面,将其拆分为构成它的组件。

例如,组件百科全书中的项目页面(Project page)将其大部分复杂性集中在头部区域。为了将数据加载等页面级关注点与标题长度等组件级关注点分开,我们将头部提取到其自己的组件中,并为其编写自己的故事。

Illustration of extracting the header component out of the rest of the page, with text reading "Decompose complex parts of a page into their own component"

使用插件测试行为、可访问性等

一旦我们编写了故事,我们可以使用插件让我们的 Storybook 更加有用。除了演示页面的各种状态外,我们还可以使用a11y 插件检查可访问性,它为我们提供了一个方便的检查状态面板,随着我们的工作而更新。更进一步,我们可以使用新宣布的交互测试在 CI 中将我们的故事作为自动化测试运行。

总结

构建页面是所有开发者必须要做的事情。在应用中构建页面困难且容易出错,因为许多状态难以重现。你最终需要通过用户流程或修改数据来处理每种状态。

故事是页面“已知良好状态”的实时文档,你可以与团队共享。你隔离开发每个页面的故事。这使你可以避免复杂的业务逻辑或混乱的应用上下文。

本文的灵感来自于我们为组件百科全书构建页面的努力,该百科全书收集了包含组件和页面的公共 Storybook,供用户浏览和学习。请在下方注册 Storybook 邮件列表,以获取组件百科全书更新和早期访问权限。或者在此提交你自己的 Storybook 的 URL

加入 Storybook 邮件列表

获取最新消息、更新和版本发布信息

7,180开发者及更多

我们正在招聘!

加入 Storybook 和 Chromatic 背后的团队。构建成千上万开发者在生产中使用的工具。远程优先。

查看职位

热门文章

Storybook 如何帮助设计师和开发者保持同步

将组件连接到设计规范、文档和反馈
loading
Varun Vachhar

社区展示 #1

Figma、SWC、Tensorflow、Spotify 播放列表等
loading
Dominic Nguyen

使用 Storybook 进行交互测试

你编写故事,Storybook 运行测试
loading
Michael Shilman
加入社区
7,180开发者及更多
为何使用为何使用 Storybook组件驱动的 UI
文档指南教程更新日志遥测
社区插件参与其中博客
展示探索项目组件词汇表
开源软件
Storybook - Storybook 中文

特别鸣谢 Netlify CircleCI