文档
Storybook Docs

侧边栏和 URL

观看视频教程

Storybook 的侧边栏列出了所有按组件分组的故事。当您有很多组件时,您可能还希望对这些组件进行分组。为此,您可以将“/”分隔符添加到 CSF 文件的 title 中,Storybook 会根据常见的词缀将故事分组。

Storybook sidebar anatomy

我们建议使用反映组件文件系统路径的嵌套方案。例如,如果您有一个文件 components/modals/Alert.js,请将 CSF 文件命名为 components/modals/Alert.stories.js 并将其标题设置为 Components/Modals/Alert

默认情况下,Storybook 会将您的顶级节点视为“根”。根在 UI 中显示为层级的“部分”。较低级别的组会显示为文件夹。

Storybook sidebar story roots

如果您希望将顶级节点显示为文件夹而不是根,您可以在 ./storybook/manager.js 中将 sidebar.showRoots 选项设置为 false

./storybook/manager.js
import { addons } from 'storybook/manager-api';
 
addons.setConfig({
  sidebar: {
    showRoots: false,
  },
});

默认情况下,Storybook 会根据组件标题和故事名称为每个故事生成一个 id。这个 id 特别用于每个故事的 URL,而该 URL 可以作为永久链接(主要是在您 发布 Storybook 时)。

考虑以下故事

FooBar.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Foo } from './Foo';
 
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: 'Foo/Bar',
  component: Foo,
} satisfies Meta<typeof Foo>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Baz: Story = {};

Storybook 的 ID 生成逻辑会为该故事赋予 id foo-bar--baz,因此链接将是 ?path=/story/foo-bar--baz

可以手动设置故事的 id,这在您想要重命名故事而不破坏永久链接时非常有用。假设您想将层级中的位置更改为 OtherFoo/Bar,并将故事名称更改为 Moo。操作方法如下:

FooBar.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 { Foo } from './Foo';
 
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: 'OtherFoo/Bar',
  component: Foo,
  id: 'Foo/Bar', // Or 'foo-bar' if you prefer
} satisfies Meta<typeof Foo>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Baz: Story = {
  name: 'Insert name here',
};

如果提供了 id,Storybook 将优先使用它而不是标题来进行 ID 生成,并优先使用 story.name 而不是导出键来进行显示。

CSF 3.0 自动标题

Storybook 6.4 引入了 CSF 3.0 作为实验性功能,允许您更简洁地编写故事。假设您已经在使用此格式编写故事。在这种情况下,您可以省略默认导出中的 title 元素,让 Storybook 根据文件的物理位置自动推断它。例如,给定以下配置和故事

.storybook/main.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: ['../src'],
};
 
export default config;

当 Storybook 加载时,故事会在侧边栏中显示为 components/My Component

自动标题与显式标题选项(如组件的 title 和故事的 name)配合使用。

src/components/Button/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 } from './Button';
 
const meta = {
  // Sets the name for the stories container
  title: 'components/Button',
  // The component name will be used if `title` is not set
  component: Button,
} satisfies Meta<typeof Button>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
// The story variable name will be used if `name` is not set
const Primary: Story = {
  // Sets the name for that particular story
  name: 'Primary',
  args: {
    label: 'Button',
  },
};

自动标题文件名的大小写

从 Storybook 6.5 开始,自动生成的故事标题不再依赖 Lodash 的 startCase。相反,文件名的 casing 被保留,从而允许对故事标题进行额外的控制。例如,components/My Component 将被定义为 components/MyComponent

如果需要,您可以恢复到以前的模式,方法是添加以下配置:

.storybook/manager.js
import { addons } from 'storybook/manager-api';
 
import startCase from 'lodash/startCase.js';
 
addons.setConfig({
  sidebar: {
    renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),
  },
});

自动标题重复文件名

除了对故事文件名 casing 的改进之外,还引入了一个新的启发式方法,用于删除冗余名称,以防文件名与目录名相同,或者如果它被称为 index.stories.js|ts。例如,以前 components/MyComponent/MyComponent.stories.js 在侧边栏中被定义为 Components/MyComponent/MyComponent。现在它将被定义为 Components/MyComponent

如果需要保留命名方案,可以将 title 元素添加到默认导出中。例如:

components/MyComponent/MyComponent.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 { MyComponent } from './MyComponent';
 
const meta = {
  /* 👇 The title prop is optional.
   * See https://storybook.org.cn/docs/configure/#configure-story-loading
   * to learn how to generate automatic titles
   */
  component: MyComponent,
  title: 'components/MyComponent/MyComponent',
} satisfies Meta<typeof MyComponent>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Default: Story = {
  args: {
    something: 'Something else',
  },
};

自动标题前缀

此外,如果您自定义 Storybook 以根据 配置对象(包括 titlePrefix)加载故事,Storybook 会自动为所有匹配的故事添加前缀。例如,假设您有以下配置:

.storybook/main.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { StorybookConfig } from '@storybook/your-framework';
 
const config: StorybookConfig = {
  framework: '@storybook/your-framework',
  stories: [
    {
      directory: '../src',
      titlePrefix: 'Custom', // 👈 Configure the title prefix
    },
  ],
};
 
export default config;

当 Storybook 为所有匹配的故事生成标题时,它们将保留 Custom 前缀。

Story Indexers

Story Indexers 是一组启发式方法,Storybook 使用这些方法根据给定的 glob 模式爬取文件系统以查找匹配的故事,然后用于生成一个 index.json(以前称为 stories.json)文件,该文件负责用必要的信息填充侧边栏。默认情况下,此启发式方法会查找包含以下方案的文件:*.stories.@(js|jsx|mjs|ts|tsx)

您可以提供自己的 indexer 以包含具有不同命名约定的故事,调整自动标题生成(超出前缀),以及许多其他用例。有关更多信息,请参阅 Story Indexers API 参考