跳转至

Storybook 组件文档 — 隔离开发、测试和记录 UI 组件的工作台


一句话说明

Storybook 是一个独立的 UI 组件开发环境,让你在不启动整个应用的情况下开发和预览每个组件的各种状态,同时自动生成交互式文档,当前版本 v8.x。


安装与配置

# 在现有项目中初始化 Storybook(自动检测框架)
npx storybook@latest init

# 手动指定框架
npx storybook@latest init --type react

# 启动 Storybook 开发服务器
npm run storybook        # 默认端口 6006

# 构建静态文档站点
npm run build-storybook

# 查看版本
npx storybook --version
// .storybook/main.ts — Storybook 主配置文件
import type { StorybookConfig } from '@storybook/react-vite';  // React+Vite 类型

const config: StorybookConfig = {
  stories: [
    '../src/**/*.mdx',          // 支持 MDX 格式的文档文件
    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',  // 匹配所有 story 文件
  ],
  addons: [
    '@storybook/addon-links',        // 页面间导航
    '@storybook/addon-essentials',   // 必备插件包(controls, docs, actions 等)
    '@storybook/addon-interactions', // 测试交互
    '@storybook/addon-a11y',         // 无障碍检查
  ],
  framework: {
    name: '@storybook/react-vite',   // 使用 React + Vite 框架
    options: {},
  },
  docs: {
    autodocs: 'tag',                 // 有 tags: ['autodocs'] 时自动生成文档
  },
};

export default config;

核心用法

// src/components/Button/Button.stories.ts — 组件 Story 文件
import type { Meta, StoryObj } from '@storybook/react';    // 类型导入
import { Button } from './Button';                          // 导入组件

// ── Meta:整个文件的元信息 ──
const meta: Meta<typeof Button> = {
  title: 'UI/Button',                    // 在 Storybook 侧边栏中的路径
  component: Button,                     // 关联的组件
  parameters: {
    layout: 'centered',                  // 居中显示
  },
  tags: ['autodocs'],                    // 自动生成文档页面
  argTypes: {                            // 控制面板配置
    variant: {
      control: 'select',                 // 用下拉框控制
      options: ['primary', 'secondary', 'danger'],
    },
    size: {
      control: 'radio',                  // 用单选框控制
      options: ['sm', 'md', 'lg'],
    },
    onClick: { action: 'clicked' },      // 点击时在 Actions 面板显示
  },
};

export default meta;                     // 必须导出 meta 作为默认导出
type Story = StoryObj<typeof meta>;      // Story 类型

// ── Story:组件的一个具体状态 ──
export const Primary: Story = {
  args: {
    variant: 'primary',      // props 值
    children: '提交',        // 按钮文字
    size: 'md',
  },
};

export const Danger: Story = {
  args: {
    variant: 'danger',
    children: '删除',
    size: 'md',
  },
};

// ── 带交互测试的 Story ──
export const WithInteraction: Story = {
  args: { children: '点击我' },
  play: async ({ canvasElement, args }) => {                // play 函数实现交互测试
    const { within, userEvent, expect } = await import('@storybook/test');
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.click(button);                          // 模拟点击
    expect(args.onClick).toHaveBeenCalled();               // 验证点击事件触发
  },
};

实战案例

// ── 生信工具 UI 组件:基因表达量热力图控件 ──
// src/components/HeatmapControls/HeatmapControls.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { HeatmapControls } from './HeatmapControls';

const meta: Meta<typeof HeatmapControls> = {
  title: '生信组件/热力图控件',             // 在侧边栏分组显示
  component: HeatmapControls,
  tags: ['autodocs'],
  argTypes: {
    colorScheme: {
      control: 'select',
      options: ['Blues', 'Reds', 'Viridis', 'RdBu'],  // 颜色方案选项
      description: '热力图颜色映射方案',
    },
    minValue: {
      control: { type: 'range', min: -5, max: 0, step: 0.5 },  // 滑块控制
      description: '颜色映射最小值',
    },
    maxValue: {
      control: { type: 'range', min: 0, max: 10, step: 0.5 },
      description: '颜色映射最大值',
    },
    showDendrogram: {
      control: 'boolean',               // 开关控制
      description: '是否显示聚类树',
    },
  },
};

export default meta;
type Story = StoryObj<typeof meta>;

// 默认状态
export const Default: Story = {
  args: {
    colorScheme: 'RdBu',
    minValue: -3,
    maxValue: 3,
    showDendrogram: true,
  },
};

// 无聚类树状态
export const NoCluster: Story = {
  args: { ...Default.args, showDendrogram: false },
};

// 自定义颜色状态
export const BlueScheme: Story = {
  args: { ...Default.args, colorScheme: 'Blues', minValue: 0 },
};
// .storybook/preview.ts — 全局装饰器配置
import type { Preview } from '@storybook/react';
import '../src/styles/global.css';     // 引入全局样式,让组件预览有正确样式

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,  // 包含 color 的 prop 自动用颜色选择器
        date: /Date$/i,                 // 包含 Date 的 prop 自动用日期选择器
      },
    },
  },
  decorators: [
    (Story) => (                        // 全局包装器,给所有 Story 加上容器
      <div style={{ padding: '24px' }}>
        <Story />
      </div>
    ),
  ],
};

export default preview;

常见报错与解决

报错原因解决方法
Cannot find module '@storybook/xxx'插件未安装运行 npx storybook@latest upgrade
Story 不显示组件export default 缺失确保文件有 export default meta
Controls 面板为空argTypes 未配置添加 argTypes 或用 autodocs
样式丢失全局 CSS 未引入.storybook/preview.ts 中 import 样式
HMR 不生效Vite 缓存问题重启 Storybook 或清除 .storybook-static

速查表

# 命令
npm run storybook           # 启动开发服务器(默认 :6006)
npm run build-storybook     # 构建静态站点到 storybook-static/
npx storybook@latest upgrade  # 升级 Storybook 版本

# Story 文件命名约定
Button.stories.ts           # TypeScript Story 文件
Button.stories.tsx          # 带 JSX 的 Story 文件
Button.mdx                  # Markdown + Story 混合文档

# 常用 Addons
addon-essentials            # controls, docs, actions, backgrounds, viewport
addon-a11y                  # 无障碍检查
addon-interactions          # play 函数交互测试
addon-coverage              # 测试覆盖率

# 部署文档站
npx chromatic               # 发布到 Chromatic(Storybook 官方云服务)

# 官方文档:https://storybook.js.org/docs