Docs
Storybook Docs

命名组件和层次结构

Watch a video tutorial

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

¥Storybook provides a powerful way to organize your stories, giving you the necessary tools to categorize, search, and filter your stories based on your organization's needs and preferences.

结构和层次结构

¥Structure and hierarchy

组织 Storybook 时,有两种构造故事的方法:隐式和显式。隐式方法 涉及依靠故事的物理位置将它们放置在侧边栏中,而 显式方法 涉及利用 title 参数来放置故事。

¥When organizing your Storybook, there are two methods of structuring your stories: implicit and explicit. The implicit method involves relying upon the physical location of your stories to position them in the sidebar, while the explicit method involves utilizing the title parameter to place the story.

Storybook sidebar hierarchy

根据你构建 Storybook 的方式,你可以看到故事层次结构由各个部分组成:

¥Based on how you structure your Storybook, you can see that the story hierarchy is made up of various parts:

  • 类别:Storybook 生成的故事和文档页面的顶层分组

    ¥Category: The top-level grouping of stories and documentation pages generated by Storybook

  • 文件夹:一个中级组织单位,将侧边栏中的组件和故事分组,代表应用的功能或部分

    ¥Folder: A mid-level organizational unit that groups components and stories in the sidebar, representing a feature or section of your application

  • 组件:一个底层组织单位,代表故事正在测试的组件

    ¥Component: A low-level organizational unit representing the component that the story is testing

  • 文档:为组件自动生成的 文档页面

    ¥Docs: The automatically generated documentation page for the component

  • 故事:单个故事测试特定的组件状态

    ¥Story: The individual story testing a specific component state

命名故事

¥Naming stories

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

¥When creating your stories, you can explicitly use the title parameter to define the story's position in the sidebar. It can also be used to group related components together in an expandable interface to help with Storybook organization providing a more intuitive experience for your users. For example:

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.js.org/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Button',
  component: Button,
};
 
export default meta;

结果如下:

¥Yields this:

Stories hierarchy without paths

分组

¥Grouping

还可以将相关组件分组到可扩展界面中,以帮助 Storybook 组织。为此,请使用 / 作为分隔符:

¥It is also possible to group related components in an expandable interface to help with Storybook organization. To do so, use the / as a separator:

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.js.org/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.js.org/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Design System/Atoms/Checkbox',
  component: CheckBox,
};
 
export default meta;

结果如下:

¥Yields this:

Stories hierarchy with paths

¥Roots

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

¥By default, the top-level grouping will be displayed as “root” in the Storybook UI (i.e., the uppercased, non-expandable items). If you need, you can configure Storybook and disable this behavior. Useful if you need to provide a streamlined experience for your users; nevertheless, if you have a large Storybook composed of multiple component stories, we recommend naming your components according to the file hierarchy.

单层提升

¥Single-story hoisting

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

¥Single-story components (i.e., component stories without siblings) whose display name exactly matches the component's name (last part of title) are automatically hoisted up to replace their parent component in the UI. For example:

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.js.org/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

由于故事导出自动为 "start 大小写"(myStory 变为 "My Story"),你的组件名称应与之匹配。或者,你可以使用 myStory.storyName = '...' 覆盖故事名称以匹配组件名称。

¥Because story exports are automatically "start cased" (myStory becomes "My Story"), your component name should match that. Alternatively, you can override the story name using myStory.storyName = '...' to match the component name.

排序故事

¥Sorting stories

开箱即用,Storybook 根据故事的导入顺序对其进行排序。但是,你可以通过将 storySort 添加到 preview.js 文件中的 options 参数来自定义此模式以满足你的需求并提供更直观的体验。

¥Out of the box, Storybook sorts stories based on the order in which they are imported. However, you can customize this pattern to suit your needs and provide a more intuitive experience by adding storySort to the options parameter in your preview.js file.

.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;

除了唯一的故事标识符之外,你还可以使用 titlename 和导入路径通过 storySort 函数对你的故事进行排序。

¥Asides from the unique story identifier, you can also use the title, name, and import path to sort your stories using the storySort function.

storySort 还可以接受配置对象。

¥The storySort can also accept a configuration object.

.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 列表中的项目不匹配的故事将出现在列表中的项目之后。

¥To sort your stories alphabetically, set method to 'alphabetical' and optionally set the locales string. To sort your stories using a custom list, use the order array; stories that don't match an item in the order list will appear after the items in the list.

order 数组可以接受嵌套数组以对第二级故事类型进行排序。例如:

¥The order array can accept a nested array to sort 2nd-level story kinds. For example:

.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;

这将导致这个故事排序:

¥Which would result in this story ordering:

  1. IntroIntro/* 故事

    ¥Intro and then Intro/* stories

  2. Pages 故事

    ¥Pages story

  3. Pages/HomePages/Home/* 故事

    ¥Pages/Home and Pages/Home/* stories

  4. Pages/LoginPages/Login/* 故事

    ¥Pages/Login and Pages/Login/* stories

  5. Pages/AdminPages/Admin/* 故事

    ¥Pages/Admin and Pages/Admin/* stories

  6. Pages/* 故事

    ¥Pages/* stories

  7. ComponentsComponents/* 故事

    ¥Components and Components/* stories

  8. 所有其他故事

    ¥All other stories

如果你希望特定类别排序到列表末尾,则可以将 * 插入 order 数组以指示 "所有其他故事" 应该去哪里:

¥If you want specific categories to sort to the end of the list, you can insert a * into your order array to indicate where "all other stories" should go:

.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 类别将显示在列表末尾。

¥In this example, the WIP category would be displayed at the end of the list.

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

¥Note that the order option is independent of the method option; stories are sorted first by the order array and then by either the method: 'alphabetical' or the default configure() import order.