antd 组件也做了同款效果!深入源码看设计模式在前端组件库的应用

一、这东西是什么

antd (Ant Design)是阿里巴巴开源的 React UI 组件库,提供丰富的企业级 UI 组件。但 antd 的价值不止于组件本身,更在于其优秀的设计模式应用

核心观点:antd 和 lodash-es 虽然领域不同,但都应用了相似的设计模式:

  • 模块化设计:组件独立,支持按需引入
  • 组合模式:通过 props 组合实现复杂功能
  • 装饰器模式:高阶组件增强功能
  • 工厂模式:统一创建相似组件

二、这东西有什么用

适用场景

  • React 项目开发
  • 需要高质量 UI 组件的企业应用
  • 学习前端设计模式的开发者
  • 需要自定义组件库的团队

能带来什么收益

  1. 代码复用:减少重复代码,提高开发效率
  2. 可维护性:清晰的架构让代码更易维护
  3. 一致性:统一的设计模式保证代码风格一致
  4. 扩展性:易于添加新功能或修改现有功能

三、官方链接

四、从源码看设计模式

1. 模块化设计(与 lodash-es 同款)

javascript 复制代码
// antd 的模块化结构
// 每个组件独立目录,支持按需引入
import { Button, Modal, Form } from 'antd';

// 或者按需引入特定组件
import Button from 'antd/es/button';
import Modal from 'antd/es/modal';

源码结构

bash 复制代码
antd/
├── es/                    # ES Module 版本
│   ├── button/
│   │   ├── index.js      # 入口文件
│   │   ├── button.js     # 主组件
│   │   └── style/        # 样式文件
│   ├── modal/
│   └── ...
├── lib/                  # CommonJS 版本
└── dist/                 # UMD 版本

2. 组合模式(Composition Pattern)

antd 的 Form 组件是组合模式的典型应用:

javascript 复制代码
// antd Form 组件使用组合模式
import { Form, Input, Button } from 'antd';

const MyForm = () => (
  <Form>
    <Form.Item name="username" rules={[{ required: true }]}>
      <Input placeholder="用户名" />
    </Form.Item>
    <Form.Item name="password" rules={[{ required: true }]}>
      <Input.Password placeholder="密码" />
    </Form.Item>
    <Form.Item>
      <Button type="primary" htmlType="submit">
        提交
      </Button>
    </Form.Item>
  </Form>
);

源码分析:Form.Item 作为容器,组合了表单控件和验证逻辑。

3. 装饰器模式(Decorator Pattern)

antd 使用高阶组件(HOC)实现装饰器模式:

javascript 复制代码
// antd 的 withConfigConsumer 高阶组件
import { ConfigConsumer } from '../config-provider/context';

function withConfigConsumer(config) {
  return function withConfigConsumerFunc(Component) {
    return function WrappedComponent(props) {
      return (
        <ConfigConsumer>
          {context => <Component {...config} {...props} {...context} />}
        </ConfigConsumer>
      );
    };
  };
}

// 使用装饰器增强组件
const EnhancedButton = withConfigConsumer({
  prefixCls: 'ant-btn'
})(Button);

4. 工厂模式(Factory Pattern)

antd 的 notification 组件使用工厂模式:

javascript 复制代码
// notification 工厂函数
import Notification from './notification';

// 创建不同类型的通知
const notification = {
  success: (config) => Notification.success(config),
  error: (config) => Notification.error(config),
  info: (config) => Notification.info(config),
  warning: (config) => Notification.warning(config),
  open: (config) => Notification.open(config),
};

// 使用
notification.success({
  message: '操作成功',
  description: '数据已保存',
});

五、如何做一个 demo 出来

1. 环境要求

  • Node.js 14+
  • React 16.8+
  • TypeScript(可选)

2. 安装命令

bash 复制代码
# 创建 React 项目
npx create-react-app antd-pattern-demo --template typescript

# 安装 antd
cd antd-pattern-demo
npm install antd

# 安装分析工具
npm install --save-dev @types/react @types/react-dom

3. 目录结构说明

bash 复制代码
antd-pattern-demo/
├── src/
│   ├── components/
│   │   ├── MyButton/      # 自定义按钮组件
│   │   ├── MyForm/        # 自定义表单组件
│   │   └── MyModal/       # 自定义弹窗组件
│   ├── patterns/          # 设计模式示例
│   │   ├── composition/   # 组合模式
│   │   ├── decorator/     # 装饰器模式
│   │   └── factory/       # 工厂模式
│   ├── App.tsx
│   └── index.tsx
├── package.json
└── tsconfig.json

4. 最小可运行示例

组合模式示例

typescript 复制代码
// src/patterns/composition/FormDemo.tsx
import React from 'react';
import { Form, Input, Button, Select } from 'antd';

const { Option } = Select;

const FormDemo: React.FC = () => {
  const onFinish = (values: any) => {
    console.log('表单值:', values);
  };

  return (
    <Form
      name="basic"
      initialValues={{ remember: true }}
      onFinish={onFinish}
      layout="vertical"
      {/* 组合 Input 和验证规则 */}
      <Form.Item
        label="用户名"
        name="username"
        rules={[
          { required: true, message: '请输入用户名' },
          { min: 3, message: '至少3个字符' }
        ]}
        <Input placeholder="请输入用户名" />
      </Form.Item>

      {/* 组合 Select 和选项 */}
      <Form.Item
        label="角色"
        name="role"
        rules={[{ required: true, message: '请选择角色' }]}
        <Select placeholder="请选择角色">
          <Option value="admin">管理员</Option>
          <Option value="user">普通用户</Option>
          <Option value="guest">访客</Option>
        </Select>
      </Form.Item>

      {/* 组合 Button 和提交逻辑 */}
      <Form.Item>
        <Button type="primary" htmlType="submit">
          提交
        </Button>
      </Form.Item>
    </Form>
  );
};

export default FormDemo;

装饰器模式示例

typescript 复制代码
// src/patterns/decorator/withLoading.tsx
import React, { ComponentType, useState, useEffect } from 'react';
import { Spin } from 'antd';

// 高阶组件:为组件添加加载状态
function withLoading<P extends object>(
  WrappedComponent: ComponentType<P>
): React.FC<P & { isLoading?: boolean }> {
  return function WithLoadingComponent(props) {
    const [loading, setLoading] = useState(props.isLoading || false);

    // 模拟异步加载
    useEffect(() => {
      if (props.isLoading) {
        setLoading(true);
        const timer = setTimeout(() => {
          setLoading(false);
        }, 2000);
        return () => clearTimeout(timer);
      }
    }, [props.isLoading]);

    if (loading) {
      return (
        <div style={{ padding: '50px', textAlign: 'center' }}>
          <Spin size="large" />
          <div style={{ marginTop: '16px' }}>加载中...</div>
        </div>
      );
    }

    return <WrappedComponent {...props as P} />;
  };
}

// 使用装饰器
const UserList: React.FC<{ users: string[] }> = ({ users }) => (
  <ul>
    {users.map((user, index) => (
      <li key={index}>{user}</li>
    ))}
  </ul>
);

const UserListWithLoading = withLoading(UserList);

// 在组件中使用
const App: React.FC = () => {
  const users = ['张三', '李四', '王五'];
  
  return (
    <div>
      <h2>用户列表(带加载效果)</h2>
      <UserListWithLoading users={users} isLoading={true} />
    </div>
  );
};

工厂模式示例

typescript 复制代码
// src/patterns/factory/NotificationFactory.tsx
import React from 'react';
import { Button, Space } from 'antd';
import { notification } from 'antd';

// 通知工厂
class NotificationFactory {
  static create(type: 'success' | 'error' | 'info' | 'warning', config: any) {
    const methods = {
      success: notification.success,
      error: notification.error,
      info: notification.info,
      warning: notification.warning,
    };

    return methods[type]({
      duration: 3,
      placement: 'topRight',
      ...config,
    });
  }

  // 预定义的通知类型
  static success(message: string, description?: string) {
    return this.create('success', { message, description });
  }

  static error(message: string, description?: string) {
    return this.create('error', { message, description });
  }

  static info(message: string, description?: string) {
    return this.create('info', { message, description });
  }

  static warning(message: string, description?: string) {
    return this.create('warning', { message, description });
  }
}

// 使用工厂
const NotificationDemo: React.FC = () => {
  const showNotification = (type: 'success' | 'error' | 'info' | 'warning') => {
    const messages = {
      success: '操作成功!',
      error: '操作失败!',
      info: '这是提示信息',
      warning: '请注意警告',
    };

    NotificationFactory[type](messages[type], '详细描述信息');
  };

  return (
    <Space>
      <Button type="primary" onClick={() => showNotification('success')}>
        成功通知
      </Button>
      <Button danger onClick={() => showNotification('error')}>
        错误通知
      </Button>
      <Button onClick={() => showNotification('info')}>
        信息通知
      </Button>
      <Button type="dashed" onClick={() => showNotification('warning')}>
        警告通知
      </Button>
    </Space>
  );
};

5. 运行项目

bash 复制代码
# 启动开发服务器
npm start

# 访问 http://localhost:3000

六、设计模式在前端开发中的应用场景

1. 组合模式(Composition)

适用场景

  • 表单组件(Form + Form.Item + Input)
  • 布局组件(Layout + Header + Content + Footer)
  • 导航菜单(Menu + Menu.Item + SubMenu)

antd 源码示例

typescript 复制代码
// antd/es/form/Form.tsx
const Form: React.FC<FormProps> = (props) => {
  return (
    <FormProvider>
      <FormContext.Provider value={formContextValue}>
        <FormComponent {...props} />
      </FormContext.Provider>
    </FormProvider>
  );
};

// Form.Item 作为子组件
Form.Item = FormItem;

2. 装饰器模式(Decorator)

适用场景

  • 权限控制(withAuth)
  • 数据加载(withLoading)
  • 错误处理(withErrorBoundary)
  • 样式增强(withStyles)

antd 源码示例

typescript 复制代码
// antd/es/config-provider/context.tsx
export const ConfigConsumer = ConfigContext.Consumer;

// 使用 ConfigConsumer 装饰组件
export function withConfigConsumer<C extends React.ComponentType<any>>(
  config: ConsumerConfig
) {
  return function withConfigConsumerFunc(
    Component: C
  ): React.ComponentType<any> {
    // 返回装饰后的组件
    return (props: any) => (
      <ConfigConsumer>
        {(context) => (
          <Component {...config} {...props} {...context} />
        )}
      </ConfigConsumer>
    );
  };
}

3. 工厂模式(Factory)

适用场景

  • 创建不同类型的弹窗(Modal.success/error/info)
  • 创建不同类型的消息(message.success/error)
  • 创建不同类型的通知(notification.success/error)

antd 源码示例

typescript 复制代码
// antd/es/modal/confirm.tsx
export default function confirm(config: ModalFuncProps) {
  // 创建确认对话框的工厂函数
  const div = document.createElement('div');
  document.body.appendChild(div);
  
  let currentConfig = { ...config, close, visible: true };
  
  function destroy() {
    // 销毁逻辑
  }
  
  function render(props: any) {
    // 渲染逻辑
  }
  
  function update(newConfig: ModalFuncProps) {
    // 更新逻辑
  }
  
  function close() {
    // 关闭逻辑
  }
  
  render(currentConfig);
  
  return {
    destroy: close,
    update,
  };
}

// 工厂方法
Modal.confirm = (props: ModalFuncProps) => confirm(props);
Modal.success = (props: ModalFuncProps) => confirm({ ...props, icon: <CheckCircleOutlined /> });
Modal.error = (props: ModalFuncProps) => confirm({ ...props, icon: <CloseCircleOutlined /> });

七、性能优化与最佳实践

1. 按需引入(与 lodash-es 同款)

typescript 复制代码
// 推荐:按需引入
import Button from 'antd/es/button';
import Form from 'antd/es/form';
import 'antd/es/button/style';
import 'antd/es/form/style';

// 不推荐:全量引入
import { Button, Form } from 'antd';
import 'antd/dist/antd.css';

2. 使用 babel-plugin-import

javascript 复制代码
// .babelrc 或 babel.config.js
{
  "plugins": [
    ["import", {
      "libraryName": "antd",
      "libraryDirectory": "es",
      "style": true
    }]
  ]
}

// 现在可以这样写,插件会自动转换
import { Button } from 'antd';
// 转换为 ↓
import Button from 'antd/es/button';
import 'antd/es/button/style';

3. 组件性能优化

typescript 复制代码
// 使用 React.memo 避免不必要的重渲染
import React, { memo } from 'react';
import { Button } from 'antd';

const MyButton = memo(({ onClick, children }) => {
  console.log('MyButton 渲染');
  return <Button onClick={onClick}>{children}</Button>;
});

// 使用 useCallback 缓存函数
const App = () => {
  const handleClick = useCallback(() => {
    console.log('按钮点击');
  }, []);
  
  return <MyButton onClick={handleClick}>点击我</MyButton>;
};

八、与 lodash-es 的对比分析

特性 lodash-es antd 共同点
模块化 ES Module 独立文件 ES Module 独立组件 都支持按需引入
Tree Shaking 支持 支持 都依赖静态分析
设计模式 函数式编程 面向对象设计模式 都注重代码组织
使用场景 工具函数 UI 组件 都提供高质量代码

核心相似点 :都通过优秀的架构设计,解决了代码复用性能优化的问题。

九、常见坑与注意事项

1. 样式问题

typescript 复制代码
// 错误:忘记引入样式
import { Button } from 'antd';
// 缺少:import 'antd/es/button/style';

// 正确:使用 babel-plugin-import 或手动引入
import Button from 'antd/es/button';
import 'antd/es/button/style';

2. 版本兼容性

json 复制代码
// package.json
{
  "dependencies": {
    "antd": "^4.0.0",  // 注意主版本号
    "react": "^16.8.0", // 需要 React 16.8+
    "react-dom": "^16.8.0"
  }
}

3. TypeScript 配置

json 复制代码
// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  }
}

4. 自定义主题

javascript 复制代码
// craco.config.js(Create React App)
const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: {
              '@primary-color': '#1DA57A', // ��改主题色
            },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

十、总结

antd 和 lodash-es 虽然解决不同问题,但都体现了优秀前端库的共同特点:

  1. 模块化设计:支持按需引入,减少打包体积
  2. 设计模式应用:组合、装饰器、工厂等模式提升代码质量
  3. 性能优化:Tree Shaking、Memoization 等技术
  4. 开发者体验:清晰的 API、完整的文档、TypeScript 支持

学习建议

  1. 阅读优秀开源库的源码,理解设计思想
  2. 在实际项目中应用设计模式
  3. 关注性能优化,特别是打包体积
  4. 保持代码的可维护性和可扩展性

最后:优秀的前端工程师不仅要会使用工具,更要理解工具背后的设计思想。antd 和 lodash-es 都是学习前端架构的绝佳教材。

如果对你有用,欢迎点赞、收藏、关注! 下一篇我们将深入分析 Vue KeepAlive 的源码实现。

参考资料

相关推荐
祁梦2 小时前
Redis从入门到入土 --- 黑马点评判断秒杀资格
java·后端
前端Hardy2 小时前
Flutter vs React Native vs HarmonyOS:谁更适合下一代跨端?2026 年技术选型终极指南
前端·flutter·react native
前端Hardy2 小时前
Vite 8 来了:彻底抛弃 Rollup 和 esbuild!Rust 重写后,快到 Webpack 连尾灯都看不见
前端·面试·vite
兆子龙2 小时前
lodash 到 lodash-es 多的不仅仅是后缀!深入源码看 ES Module 带来的性能与体积优化
java·前端·架构
heyCHEEMS2 小时前
用 分段渲染 解决小程序长列表卡顿问题
前端·微信小程序
仨孩子的爹2 小时前
Vue实战|折腾两天,终于找到业务打印救星:vue-print-designer网页套打插件接入
前端
Memory_荒年2 小时前
限流算法:当你的系统变成“网红景点”,如何避免被游客挤垮?
java·后端
我命由我123452 小时前
Git 问题:Author identity unknown*** Please tell me who you are.
java·服务器·git·后端·学习·java-ee·学习方法
Arya_aa2 小时前
java中的方法重写,重载,接口和抽象类
java