文档
Storybook 文档

参数

观看视频教程

故事是一个带有参数集的组件,这些参数定义了组件的渲染方式。“参数”是 Storybook 用于在单个 JavaScript 对象中定义这些参数的机制。参数可用于动态更改 props、插槽、样式、输入等。它允许 Storybook 及其插件实时编辑组件。您**无需**修改底层组件代码即可使用参数。

当参数的值发生变化时,组件会重新渲染,允许您通过影响参数的插件与 Storybook 的 UI 中的组件进行交互。

了解如何在简介中编写故事以及编写故事的原因。有关参数工作原理的详细信息,请继续阅读。

参数对象

args 对象可以在故事组件全局级别定义。它是一个 JSON 可序列化对象,由具有匹配有效值类型的字符串键组成,可以传递给框架中的组件。

故事参数

要定义单个故事的参数,请使用args CSF 故事键

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 = {
  args: {
    primary: true,
    label: 'Button',
  },
};

这些参数仅适用于它们所附加的故事,尽管您可以通过 JavaScript 对象重用重用它们。

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};
 
export const PrimaryLongName: Story = {
  args: {
    ...Primary.args,
    label: 'Primary with a really long name',
  },
};

在上面的示例中,我们使用了 ES 2015 的对象展开功能。

组件参数

您也可以在组件级别定义参数;除非您覆盖它们,否则它们将应用于该组件的所有故事。为此,请在default CSF 导出上使用args

Button.stories.ts|tsx
import type { Meta } from '@storybook/react';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
  //👇 Creates specific argTypes
  argTypes: {
    backgroundColor: { control: 'color' },
  },
  args: {
    //👇 Now all Button stories will be primary.
    primary: true,
  },
};
 
export default meta;
type Story = StoryObj<typeof Button>;

全局参数

您也可以在全局级别定义参数;除非您覆盖它们,否则它们将应用于每个组件的所有故事。为此,请在preview.js的默认导出中定义args 属性

.storybook/preview.ts
// Replace your-renderer with the renderer you are using (e.g., react, vue3, angular, etc.)
import { Preview } from '@storybook/your-renderer';
 
const preview: Preview = {
  // The default value of the theme arg for all stories
  args: { theme: 'light' },
};
 
export default preview;

对于全局参数的大多数用法,全局变量是定义全局应用设置(例如主题)的更好工具。使用全局变量使用户能够使用工具栏菜单更改值。

参数组合

您可以将故事的参数分开,以在其他故事中进行组合。以下是如何组合同一组件的多个故事的参数。

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};
 
export const Secondary: Story = {
  args: {
    ...Primary.args,
    primary: false,
  },
};

如果您发现自己对组件的大多数故事都重复使用相同的参数,则应考虑使用组件级参数

参数在为由其他组件组成的复合组件编写故事时非常有用。复合组件通常会将其参数不变地传递给其子组件,类似地,其故事可以是其子组件故事的组合。使用参数,您可以直接组合参数

Page.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { Page } from './Page';
 
//👇 Imports all Header stories
import * as HeaderStories from './Header.stories';
 
const meta: Meta<typeof Page> = {
  component: Page,
};
 
export default meta;
type Story = StoryObj<typeof Page>;
 
export const LoggedIn: Story = {
  args: {
    ...HeaderStories.LoggedIn.args,
  },
};

参数可以修改组件的任何方面

您可以在故事中使用参数来配置组件的外观,类似于您在应用程序中执行的操作。例如,以下是如何使用footer 参数填充子组件

Page.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { Page } from './Page';
 
type PagePropsAndCustomArgs = React.ComponentProps<typeof Page> & { footer?: string };
 
const meta: Meta<PagePropsAndCustomArgs> = {
  component: Page,
  render: ({ footer, ...args }) => (
    <Page {...args}>
      <footer>{footer}</footer>
    </Page>
  ),
};
export default meta;
 
type Story = StoryObj<PagePropsAndCustomArgs>;
 
export const CustomFooter: Story = {
  args: {
    footer: 'Built with Storybook',
  },
};

通过 URL 设置参数

您还可以通过在 URL 中添加 args 查询参数来覆盖活动故事的初始参数集。通常,您会使用 Controls 附加组件 来处理此操作。例如,以下是如何在 Storybook 的 URL 中设置 sizestyle 参数:

?path=/story/avatar--default&args=style:rounded;size:100

为了防止 XSS 攻击,URL 中提供的参数键和值仅限于字母数字字符、空格、下划线和连字符。任何其他类型都将被忽略并从 URL 中删除,但您仍然可以在 Controls 附加组件中以及 故事内部 使用它们。

args 参数始终是一组以分号 ; 分隔的 key: value 对。值将被强制转换为它们各自的 argTypes(可能已自动推断)。支持对象和数组。可以通过在前面加上感叹号 ! 来设置特殊值 nullundefined。例如,args=obj.key:val;arr[0]:one;arr[1]:two;nil:!null 将被解释为

{
  obj: { key: 'val' },
  arr: ['one', 'two'],
  nil: null
}

同样,日期和颜色也提供了特殊格式。日期对象将被编码为 !date(value),其中 value 表示为 ISO 日期字符串。颜色被编码为 !hex(value)!rgba(value)!hsla(value)。请注意,rgb(a) 和 hsl(a) 不应在 URL 中包含空格或百分号。

通过 URL 指定的参数将扩展并覆盖故事上设置的任何参数默认值。

在故事中设置参数

交互式组件通常需要由其包含的组件或页面控制,以响应事件、修改其状态并在 UI 中反映这些更改。例如,当用户切换开关组件时,开关应被选中,并且 Storybook 中显示的参数应反映更改。为了实现这一点,您可以使用由 @storybook/preview-api 导出的 useArgs API

my-component/component.stories.ts|tsx
import { StoryObj, Meta } from '@storybook/react';
import { useArgs } from '@storybook/preview-api';
import { Checkbox } from './checkbox';
 
const meta: Meta<typeof Checkbox> = {
  title: 'Inputs/Checkbox',
  component: Checkbox,
};
export default meta;
 
type Story = StoryObj<typeof Checkbox>;
 
export const Example: Story = {
  args: {
    isChecked: false,
    label: 'Try Me!',
  },
  /**
   * 👇 To avoid linting issues, it is recommended to use a function with a capitalized name.
   * If you are not concerned with linting, you may use an arrow function.
   */
  render: function Render(args) {
    const [{ isChecked }, updateArgs] = useArgs();
 
    function onChange() {
      updateArgs({ isChecked: !isChecked });
    }
 
    return <Checkbox {...args} onChange={onChange} isChecked={isChecked} />;
  },
};

映射到复杂的参数值

诸如 JSX 元素之类的复杂值无法序列化到管理器(例如,Controls 附加组件)或与 URL 同步。可以使用 argTypes 中的 mapping 属性将参数值从简单字符串“映射”到复杂类型,以解决此限制。它适用于任何参数,但在与 select 控制类型一起使用时最有效。

Example.stories.ts|tsx
// Replace your-renderer with the renderer you are using (e.g., react, vue3, angular, etc.)
import type { Meta } from '@storybook/your-renderer';
 
import { Example } from './Example';
 
const meta: Meta<typeof Example> = {
  component: Example,
  argTypes: {
    label: {
      options: ['Normal', 'Bold', 'Italic'],
      mapping: {
        Bold: <b>Bold</b>,
        Italic: <i>Italic</i>,
      },
    },
  },
};
 
export default meta;

请注意,mapping 不必是详尽的。如果参数值不是 mapping 的属性,则该值将直接使用。 mapping 中的键始终对应于参数的,而不是它们在 options 数组中的索引。

在附加组件中使用参数

如果您正在 编写附加组件 并希望读取或更新参数,请使用由 @storybook/manager-api 导出的 useArgs 钩子

my-addon/src/manager.js|ts
import { useArgs } from '@storybook/manager-api';
 
const [args, updateArgs, resetArgs] = useArgs();
 
// To update one or more args:
updateArgs({ key: 'value' });
 
// To reset one (or more) args:
resetArgs((argNames: ['key']));
 
// To reset all args
resetArgs();