Decorators
观看视频教程
装饰器是一种将 story 包装在额外的“渲染”功能中的方法。许多插件定义了装饰器,以使用额外的渲染来增强您的 story 或收集有关您的 story 如何渲染的详细信息。
在编写 story 时,装饰器通常用于使用额外的标记或上下文模拟来包装 story。
使用额外的标记包装 story
某些组件需要“harness”才能以有用的方式渲染。例如,如果组件一直运行到其边缘,您可能希望在 Storybook 内部间隔它。使用装饰器为组件的所有 story 添加间距。
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 上下文,其中包含以下属性
args
- story 参数。您可以在装饰器中使用一些args
,并将它们放在 story 实现本身中。argTypes
- Storybook 的 argTypes 允许您自定义和微调您的 storiesargs
。globals
- Storybook 全局 globals。特别是,您可以使用 工具栏功能,以便您可以使用 Storybook 的 UI 更改这些值。hooks
- Storybook 的 API hooks(例如,useArgs)。parameters
- story 的静态元数据,最常用于控制 Storybook 的功能和插件的行为。viewMode
- Storybook 当前的活动窗口(例如,canvas、docs)。
此上下文可用于根据 story 的参数或其他元数据调整装饰器的行为。例如,您可以创建一个装饰器,允许您通过定义 parameters.pageLayout = 'page'
(或 'page-mobile'
) 来选择性地将布局应用于 story:
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;
有关另一个示例,请参阅关于配置 mock 提供程序的部分,该部分演示了如何使用相同的技术来更改提供给组件的主题。
使用装饰器提供数据
如果您的组件是“连接的”并且需要侧加载的数据才能渲染,则可以使用装饰器以模拟方式提供该数据,而无需重构组件以将该数据作为 arg 接收。有几种技术可以实现此目的。取决于您加载数据的方式。在 在 Storybook 中构建页面 部分阅读更多内容。
Story 装饰器
要为单个 story 定义装饰器,请在命名导出上使用 decorators
键
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>
),
],
};
确保 story 仍然是正在测试的组件的“纯”渲染,并且任何额外的 HTML 或组件仅用作装饰器,这很有用。特别是,当您这样做时,Source 文档块效果最佳。
组件装饰器
要为组件的所有 story 定义装饰器,请使用默认 CSF 导出的 decorators
键
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|ts
文件的 decorators
导出为所有 story 设置装饰器(这是您配置所有 story 的文件)
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;
装饰器继承
与 parameters 类似,装饰器可以在全局级别、组件级别和单个 story 级别定义(正如我们所见)。
一旦 story 渲染,所有与 story 相关的装饰器将按以下顺序运行
- 全局装饰器,按照定义的顺序
- 组件装饰器,按照定义的顺序
- Story 装饰器,按照定义的顺序,从最内层的装饰器开始,向外并在层级结构中以相同的顺序向上工作