文档
Storybook 文档

装饰器

观看视频教程

装饰器是一种将故事包装在额外“渲染”功能中的方法。许多插件定义装饰器以使用额外渲染增强你的故事或收集有关故事渲染方式的详细信息。

在编写故事时,装饰器通常用于使用额外的标记或上下文模拟来包装故事。

使用额外标记包装故事

某些组件需要一个“框架”才能以有用的方式渲染。例如,如果组件一直延伸到其边缘,你可能希望在 Storybook 中为其添加间距。使用装饰器为组件的所有故事添加间距。

Story without padding

YourComponent.stories.ts|tsx
import type { Meta } from '@storybook/react';
 
import { YourComponent } from './YourComponent';
 
const meta: Meta<typeof YourComponent> = {
  component: YourComponent,
  decorators: [
    (Story) => (
      <div style={{ margin: '3em' }}>
        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}
        <Story />
      </div>
    ),
  ],
};
 
export default meta;

Story with padding

用于模拟的“上下文”

装饰器函数的第二个参数是**故事上下文**,其中包含以下属性

  • args - 故事参数。你可以在你的装饰器中使用一些args,并将其放入故事实现本身。
  • argTypes- Storybook 的argTypes 允许你自定义和微调你的故事args
  • globals - Storybook 范围内的全局变量。特别是,你可以使用工具栏功能来允许你使用 Storybook 的 UI 更改这些值。
  • hooks - Storybook 的 API 钩子(例如,useArgs)。
  • parameters- 故事的静态元数据,最常用于控制 Storybook 功能和插件的行为。
  • viewMode- Storybook 当前活动的窗口(例如,画布、文档)。

此上下文可用于根据故事的参数或其他元数据调整装饰器的行为。例如,你可以创建一个装饰器,允许你通过定义parameters.pageLayout = 'page'(或'page-mobile')来选择性地将布局应用于故事:

.storybook/preview.tsx
import React from 'react';
 
import type { Preview } from '@storybook/react';
 
const preview: Preview = {
  decorators: [
    // 👇 Defining the decorator in the preview file applies it to all stories
    (Story, { parameters }) => {
      // 👇 Make it configurable by reading from parameters
      const { pageLayout } = parameters;
      switch (pageLayout) {
        case 'page':
          return (
            // Your page layout is probably a little more complex than this ;)
            <div className="page-layout"><Story /></div>
          );
        case 'page-mobile':
          return (
            <div className="page-mobile-layout"><Story /></div>
          );
        default:
          // In the default case, don't apply a layout
          return <Story />;
      }
    },
  ],
};
 
export default preview;

有关另一个示例,请参阅有关配置模拟提供程序的部分,其中演示了如何使用相同技术来更改提供给组件的主题。

使用装饰器提供数据

如果你的组件是“连接”的,并且需要侧加载数据才能渲染,则可以使用装饰器以模拟的方式提供这些数据,而无需重构组件以将这些数据作为参数。有几种方法可以实现这一点。具体取决于你加载这些数据的方式。在Storybook 中构建页面部分中了解更多信息。

故事装饰器

要为单个故事定义装饰器,请在命名导出上使用decorators

Button.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
export const Primary: Story = {
  decorators: [
    (Story) => (
      <div style={{ margin: '3em' }}>
        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}
        <Story />
      </div>
    ),
  ],
};

确保故事保持被测组件的“纯”渲染,并且任何额外的 HTML 或组件仅用作装饰器非常有用。特别是当你这样做时,源代码文档块效果最佳。

组件装饰器

要为组件的所有故事定义装饰器,请使用默认 CSF 导出的decorators

Button.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
  decorators: [
    (Story) => (
      <div style={{ margin: '3em' }}>
        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}
        <Story />
      </div>
    ),
  ],
};
 
export default meta;

全局装饰器

我们还可以通过 .storybook/preview.js 文件(这是您配置所有故事的文件)的 decorators 导出设置所有故事的装饰器。

.storybook/preview.tsx
import React from 'react';
 
import { Preview } from '@storybook/react';
 
const preview: Preview = {
  decorators: [
    (Story) => (
      <div style={{ margin: '3em' }}>
        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}
        <Story />
      </div>
    ),
  ],
};
 
export default preview;

装饰器继承

与参数类似,装饰器可以在全局、组件级别和单个故事(如我们所见)中定义。

一旦故事渲染,所有与故事相关的装饰器都将按照以下顺序运行

  • 全局装饰器,按照定义的顺序
  • 组件装饰器,按照定义的顺序
  • 故事装饰器,按照定义的顺序