You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Storybook中实现Button组件Variant联动ColorVariant的动态控制

解决Storybook中React TypeScript Button组件Variant与ColorVariant的联动问题

问题描述

我有一个React TypeScript Button组件,通过泛型实现了主Variant(normal、fill、outline)和ColorVariant的类型联动——选择不同主Variant时,ColorVariant只能选对应允许的值。但用Storybook Autodocs生成文档时,系统识别不了这个联动逻辑:Variant只显示normal选项,ColorVariant仅显示primary选项,而且无法根据选中的Variant动态切换可选值。

解决方案

要实现Storybook里的动态联动,需要调整组件类型适配Storybook的类型推断,同时利用Storybook的argTypes和controls钩子来动态更新选项。

步骤1:优化组件类型(适配Storybook)

Storybook对泛型组件的类型支持有限,我们可以导出一个包含所有可能Props组合的类型,帮助Storybook识别完整参数:

// 在Button组件文件中添加
export type ButtonAllProps = {
  [T in keyof typeof variants]: ButtonProps<T>;
}[keyof typeof variants];

步骤2:重构Storybook配置

修改Storybook的meta配置,添加动态联动逻辑,确保所有主Variant都显示,且ColorVariant随Variant切换:

import type { Meta, StoryObj } from '@storybook/react';
import { Button, variants, colorVariants } from './Button';

// 提取组件的实际Props类型,避免泛型干扰Storybook识别
type ButtonProps = typeof Button extends React.ComponentType<infer P> ? P : never;

const meta: Meta<ButtonProps> = {
  component: Button,
  tags: ['autodocs'],
  // 默认参数
  args: {
    height: 48,
    width: 100,
    radiusVariant: 4,
    children: 'Button!',
    variant: 'normal',
    colorVariant: 'primary',
  },
  argTypes: {
    variant: {
      control: 'select',
      // 显示所有主Variant选项
      options: Object.keys(variants) as Array<keyof typeof variants>,
      description: '主变体类型',
    },
    colorVariant: {
      control: 'select',
      // 初始选项对应normal的ColorVariant
      options: Object.keys(colorVariants.normal) as Array<keyof typeof colorVariants['normal']>,
      description: '颜色变体,随主变体变化',
    },
  },
  // 核心:实现Variant切换时ColorVariant的动态更新
  parameters: {
    controls: {
      onChange: (args: ButtonProps, changedArg: keyof ButtonProps) => {
        if (changedArg === 'variant') {
          const selectedVariant = args.variant as keyof typeof variants;
          // 更新ColorVariant的可选值为当前主Variant对应的选项
          meta.argTypes.colorVariant.options = Object.keys(colorVariants[selectedVariant]) as Array<any>;
          // 重置ColorVariant为当前主Variant的第一个可选值
          args.colorVariant = Object.keys(colorVariants[selectedVariant])[0] as any;
        }
        return args;
      },
    },
  },
};

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

// 可选:定义各个主变体的快捷故事,方便快速查看效果
export const Normal: Story = {
  args: {
    variant: 'normal',
    colorVariant: 'primary',
  },
  parameters: {
    backgrounds: { default: 'dawn' },
  },
};

export const Fill: Story = {
  args: {
    variant: 'fill',
    colorVariant: 'primary',
  },
};

export const Outline: Story = {
  args: {
    variant: 'outline',
    colorVariant: 'primary',
  },
};

关键逻辑说明

  1. 类型适配:通过ButtonProps别名提取组件的实际Props类型,解决泛型导致Storybook无法识别完整参数的问题。
  2. 全Variant展示:直接用Object.keys(variants)作为Variant的选项列表,确保所有主Variant都显示在下拉菜单中。
  3. 动态联动:利用controls.onChange钩子,当Variant改变时,自动更新ColorVariant的可选选项,并重置为当前主Variant的第一个有效值。

效果验证

  • 在Storybook的Controls面板中,切换Variant下拉选项,ColorVariant的可选值会自动同步为对应主Variant允许的选项。
  • Autodocs会正确展示所有主Variant选项,且ColorVariant的描述会明确其随主变体变化的特性。

内容的提问来源于stack exchange,提问作者Saman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:36:02