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

Atomic Design结合Storybook开发时Modal动态插入Atoms的实现问题

Atomic Design 模态框(Modal)分子组件动态传入原子组件解决方案

现有实现问题梳理

  • 节点渲染逻辑错误:如果传入的test是函数类型组件,直接写{test}不会触发渲染,需要执行函数或作为组件调用
  • 结构位置错误:自定义内容放在了header容器标签外部,样式会出现错位
  • Prop命名语义模糊:test命名无法明确对应区域,扩展多区域配置时维护成本极高
  • 区域配置不完整:仅支持header区域自定义,无法覆盖body、footer的灵活配置需求

修正后组件实现

采用具名Prop插槽思路,分别开放header、body、footer三个可配置区域,支持传入任意React节点(包括原子组件、组合元素、纯文本等):

export default function ModalMolecule({ header, body, footer, ...props }) {
    return (
        <>
            <div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
                <div className="relative w-auto my-6 mx-auto max-w-3xl">
                    {/*content*/}
                    <div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
                        {/*header:仅传入内容时渲染容器*/}
                        {header && (
                            <div className="flex items-start justify-between p-5 border-b border-solid border-blueGray-200 rounded-t">
                                {header}
                            </div>
                        )}
                        {/*body*/}
                        {body && (
                            <div className="relative p-6 flex-auto">
                                {body}
                            </div>
                        )}
                        {/*footer*/}
                        {footer && (
                            <div className="flex items-center justify-end p-6 border-t border-solid border-blueGray-200 rounded-b">
                                {footer}
                            </div>
                        )}
                    </div>
                </div>
            </div>
            <div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
        </>
    );
}

调用方式说明

普通场景(无内部状态依赖)

直接传入JSX节点即可,无需包裹函数:

import ButtonAtom from '../atoms/Button';

// 场景1:Header仅渲染标题
<ModalMolecule 
  header={<h3>弹窗标题</h3>}
  body={<div>弹窗内容区域</div>}
  footer={<ButtonAtom type="primary">确认</ButtonAtom>}
/>

// 场景2:Header放置3个按钮原子
<ModalMolecule 
  header={
    <>
      <ButtonAtom type="text">返回</ButtonAtom>
      <h3>编辑页面</h3>
      <ButtonAtom type="text">帮助</ButtonAtom>
    </>
  }
  body={<div>编辑表单内容</div>}
  footer={
    <>
      <ButtonAtom>取消</ButtonAtom>
      <ButtonAtom type="primary">保存</ButtonAtom>
    </>
  }
/>

特殊场景(需要使用Modal内部状态)

如果自定义内容需要用到Modal内部的关闭、可见状态等参数,可修改组件支持渲染函数入参:

// 组件内部渲染逻辑调整,注入内部状态
{typeof header === 'function' ? header({ close: props.onClose, visible: props.visible }) : header}

// 调用时传入渲染函数
<ModalMolecule 
  header={({close}) => (
    <>
      <h3>带关闭按钮的标题</h3>
      <ButtonAtom onClick={close}>关闭</ButtonAtom>
    </>
  )}
/>

Storybook 配置优化

可针对不同使用场景单独配置Storybook示例,覆盖所有适配需求:

import ButtonAtom from '../atoms/Button';

export default {
    title: "Molecules/Modal",
    component: ModalMolecule,
};

const Template = (args) => <ModalMolecule {...args} />;

// 基础弹窗示例
export const Basic = Template.bind({});
Basic.args = {
    header: <h3>基础弹窗</h3>,
    body: <div>这是基础弹窗的内容</div>,
    footer: <ButtonAtom type="primary">确认</ButtonAtom>
};

// Header带多按钮示例
export const HeaderWithMultiButtons = Template.bind({});
HeaderWithMultiButtons.args = {
    header: <>
        <ButtonAtom type="text">返回</ButtonAtom>
        <h3>编辑弹窗</h3>
        <ButtonAtom type="text">导出</ButtonAtom>
    </>,
    body: <div>编辑表单内容区域</div>,
    footer: <>
        <ButtonAtom>取消</ButtonAtom>
        <ButtonAtom type="primary">保存</ButtonAtom>
    </>
};

扩展优化建议

  • 增加默认值:未传入header时默认渲染带关闭按钮的通用头部,减少重复代码
  • TS类型约束:给Props增加类型定义,限制传入值为ReactNode类型,避免非法值报错
  • 尺寸适配:新增size Prop控制弹窗宽度,覆盖不同场景的尺寸需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:03:05