文档
Storybook 文档

命名组件和层级结构

观看视频教程

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

结构和层级结构

在组织 Storybook 时,有两种构建故事的结构方法:**隐式**和**显式**。 隐式方法 依赖于故事的物理位置来将其放置在侧边栏中,而 显式方法 则使用 title 参数来放置故事。

Storybook sidebar hierarchy

根据你构建 Storybook 的方式,你可以看到故事层级结构由不同的部分组成。

  • **类别**:Storybook 生成的故事和文档页面的顶级分组。
  • **文件夹**:一个中间级别的组织单元,在侧边栏中对组件和故事进行分组,代表应用程序的功能或部分。
  • **组件**:一个低级别的组织单元,代表故事正在测试的组件。
  • **文档**:组件的自动生成的 文档页面
  • **故事**:测试特定组件状态的单个故事。

命名故事

创建故事时,你可以显式地使用 title 参数来定义故事在侧边栏中的位置。它还可以用于 分组 相关的组件,并将它们放在可扩展的界面中,以帮助组织 Storybook,为用户提供更直观的体验。例如:

Button.stories.ts
// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  /* 👇 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,
};
 
export default meta;

生成以下内容

Stories hierarchy without paths

分组

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

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  /* 👇 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,
};
 
export default meta;
CheckBox.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';
 
import { CheckBox } from './Checkbox';
 
const meta: Meta<typeof CheckBox> = {
  /* 👇 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,
};
 
export default meta;

生成以下内容

Stories hierarchy with paths

默认情况下,顶级分组将在 Storybook UI 中显示为“根”(即大写、不可扩展的项目)。如果需要,可以 配置 Storybook 并禁用此行为。这在需要为用户提供简化体验时很有用;但是,如果你的 Storybook 由多个组件故事组成,我们建议根据文件层级结构命名你的组件。

单故事提升

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

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button as ButtonComponent } from './Button';
 
const meta: Meta<typeof ButtonComponent> = {
  /* 👇 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,
};
 
export default meta;
type Story = StoryObj<typeof ButtonComponent>;
 
// 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

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

排序故事

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

.storybook/preview.ts
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      // The `a` and `b` arguments in this function have a type of `import('@storybook/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, vue3)
import { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  parameters: {
    options: {
      storySort: {
        method: '',
        order: [],
        locales: '',
      },
    },
  },
};
 
export default preview;
字段类型描述必填默认值示例
method字符串告诉 Storybook 以何种顺序显示故事Storybook 配置'alphabetical'
order数组要显示的故事,按提供的名称排序空数组 []['Intro', 'Components']
includeNames布尔值在排序计算中包含故事名称falsetrue
locales字符串需要显示的语言环境系统语言环境en-US

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

order 数组可以接受嵌套数组以对二级 Story Kind 进行排序。例如

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

这将导致以下故事排序

  1. IntroIntro/* 故事
  2. Pages 故事
  3. Pages/HomePages/Home/* 故事
  4. Pages/LoginPages/Login/* 故事
  5. Pages/AdminPages/Admin/* 故事
  6. Pages/* 故事
  7. ComponentsComponents/* 故事
  8. 所有其他故事

如果希望特定类别排序到列表的末尾,您可以在 order 数组中插入一个 * 来指示“所有其他故事”应该放在哪里

.storybook/preview.ts
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { 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 选项;故事首先按 order 数组排序,然后按 method: 'alphabetical' 或默认的 configure() 导入顺序排序。