加入直播会话:周四,美国东部时间上午 11 点,Storybook 9 发布及 AMA
文档
Storybook 文档

命名组件和层级结构

观看视频教程

Storybook 提供了一种强大的方式来组织您的 Story,为您提供必要的工具,以便根据您的组织需求和偏好对 Story 进行分类、搜索和过滤。

结构和层级结构

在组织 Storybook 时,有两种结构化 Story 的方法:**隐式**和**显式**。**隐式方法**依赖 Story 的物理位置来在侧边栏中定位它们,而**显式方法**则利用 title 参数来放置 Story。

Storybook sidebar hierarchy

根据您组织 Storybook 的方式,您可以看到 Story 层级结构由多个部分组成

  • **类别**:由 Storybook 生成的 Story 和文档页面的顶层分组
  • **文件夹**:用于在侧边栏中对组件和 Story 进行分组的中层组织单元,代表应用程序的某个功能或部分
  • **组件**:代表 Story 正在测试的组件的底层组织单元
  • **文档**:组件的自动生成的**文档页面**
  • **Story**:测试特定组件状态的单个 Story

命名 Story

创建 Story 时,您可以显式使用 title 参数来定义 Story 在侧边栏中的位置。它还可以用于在可展开的界面中将相关组件**分组**在一起,以帮助 Storybook 的组织,为用户提供更直观的体验。例如

Button.stories.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta = {
  /* 👇 The title prop is optional.
   * See https://storybook.org.cn/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Button',
  component: Button,
} satisfies Meta<typeof Button>;
 
export default meta;

效果如下

Stories hierarchy without paths

分组

也可以在可展开的界面中对相关组件进行分组,以帮助 Storybook 的组织。为此,请使用 / 作为分隔符

Button.stories.ts|tsx
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta = {
  /* 👇 The title prop is optional.
   * See https://storybook.org.cn/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Design System/Atoms/Button',
  component: Button,
} satisfies Meta<typeof Button>;
 
export default meta;
CheckBox.stories.ts|tsx
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta } from '@storybook/your-framework';
 
import { CheckBox } from './Checkbox';
 
const meta = {
  /* 👇 The title prop is optional.
   * See https://storybook.org.cn/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Design System/Atoms/Checkbox',
  component: CheckBox,
} satisfies Meta<typeof CheckBox>;
 
export default meta;

效果如下

Stories hierarchy with paths

根层级

默认情况下,顶级分组在 Storybook UI 中显示为“根层级”(即,大写、不可展开的项目)。如果需要,您可以**配置 Storybook**并禁用此行为。如果您需要为用户提供精简的体验,这很有用;但是,如果您的 Storybook 包含大量组件 Story,我们建议根据文件层级结构命名您的组件。

单 Story 提升

单 Story 组件(即,没有**同级**的组件 Story),其**显示名称**与组件名称(title 的最后一部分)完全匹配时,会自动提升以替换 UI 中的父组件。例如

Button.stories.ts|tsx
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button as ButtonComponent } from './Button';
 
const meta = {
  /* 👇 The title prop is optional.
   * See https://storybook.org.cn/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Design System/Atoms/Button',
  component: ButtonComponent,
} satisfies Meta<typeof ButtonComponent>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
// This is the only named export in the file, and it matches the component name
export const Button: Story = {};

Stories hierarchy with single story hoisting

由于 Story 导出会自动进行“首字母大写”(myStory 变为 "My Story"),您的组件名称应该与此匹配。或者,您可以使用 myStory.storyName = '...' 来覆盖 Story 名称以匹配组件名称。

排序 Story

默认情况下,Storybook 根据导入顺序对 Story 进行排序。但是,您可以通过在 preview.js 文件中的 options 参数中添加 storySort 来自定义此模式,以满足您的需求并提供更直观的体验。

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.
      storySort: (a, b) =>
        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),
    },
  },
};
 
export default preview;

除了唯一的 Story 标识符外,您还可以使用 titlename 和导入路径来使用 storySort 函数对 Story 进行排序。

storySort 还可以接受一个配置对象。

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      storySort: {
        method: '',
        order: [],
        locales: '',
      },
    },
  },
};
 
export default preview;
字段类型描述必需默认值示例
method字符串告诉 Storybook 如何显示 Story 的顺序Storybook configuration'alphabetical'
order数组按提供的名称排序要显示的 Story空数组 []['Intro', 'Components']
includeNames布尔值在排序计算中包含 Story 名称
locales字符串需要显示的区域设置系统区域设置en-US

要按字母顺序排序 Story,将 method 设置为 'alphabetical',并可选地设置 locales 字符串。要使用自定义列表排序 Story,请使用 order 数组;不与 order 列表中的项目匹配的 Story 将出现在列表中的项目之后。

order 数组可以接受一个嵌套数组来对二级 Story 类型进行排序。例如

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      storySort: {
        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],
      },
    },
  },
};
 
export default preview;

这将导致 Story 排序如下

  1. Intro,然后是 Intro/* Story
  2. Pages Story
  3. Pages/HomePages/Home/* Story
  4. Pages/LoginPages/Login/* Story
  5. Pages/AdminPages/Admin/* Story
  6. Pages/* Story
  7. ComponentsComponents/* Story
  8. 所有其他 Story

如果您想将特定类别排序到列表末尾,可以在您的 order 数组中插入一个 * 来指示“所有其他 Story”应该放置的位置

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      storySort: {
        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],
      },
    },
  },
};
 
export default preview;

在此示例中,WIP 类别将显示在列表末尾。

请注意,order 选项独立于 method 选项;Story 首先按 order 数组排序,然后按 method: 'alphabetical' 或默认的 configure() 导入顺序排序。