Ant Design 结合 React 参考 Vben 逻辑实现的描述列表组件封装实践
前言
在现代前端开发中,组件化是提高代码复用性和维护性的关键。本文将介绍如何基于 Ant Design 的 Descriptions 组件,结合 React 和 TypeScript,参考 Vben Admin 的设计思想,封装一个功能完善、灵活易用的描述列表组件。
组件设计思路
需求分析
描述列表(Description List)通常用于展示对象的详细信息,如用户资料、订单详情等。一个高质量的描述列表组件需要具备以下特性:
技术选型
-
UI 基础:Ant Design 的 Descriptions 组件
-
框架:React 18
-
类型系统:TypeScript
-
设计参考:Vben Admin 的组件封装思想
核心实现
1. 类型定义(typing.ts)
首先定义组件所需的类型,确保类型安全:
import type { ReactNode } from \'react\';import type { DescriptionsProps } from \'antd\';// 描述项配置接口export interface DescItem { labelMinWidth?: number; contentMinWidth?: number; labelStyle?: React.CSSProperties; field: string; label: ReactNode; span?: number; show?: (data: Record) => boolean; render?: (value: any, data: Record) => ReactNode;}// 组件属性接口export interface DescriptionProps extends AntDescriptionsProps { schema?: DescItem[]; data?: Record; column?: number;}// 组件实例接口export interface DescInstance { setDescProps: (props: Partial) => void;}
2. 组件封装(Description.tsx)
使用 forwardRef 转发 ref,结合 useState 管理动态 props,通过 useImperativeHandle 暴露实例方法:
import React, { useRef, useState, useImperativeHandle, forwardRef } from \"react\";import { Descriptions } from \"antd\";import type { DescriptionProps, DescInstance, DescItem } from \"./typing\";const Description = forwardRef((props, ref) => { const [innerProps, setInnerProps] = useState(props); const mergedProps = { ...innerProps, ...props }; const { schema, data, column = 2, bordered = true, contentStyle, labelStyle, size = \"default\", ...descriptionsProps } = mergedProps; useImperativeHandle( ref, () => ({ setDescProps: (newProps) => { setInnerProps((prev) => ({ ...prev, ...newProps })); }, }), [] ); const renderLabel = ({ label, labelMinWidth }: DescItem) => { if (!labelMinWidth || !labelStyle) return label; return <div style={{ minWidth: `${labelMinWidth}px`, ...labelStyle }}>{label}
3. 自定义 Hook(useDescription.ts)
封装自定义 Hook 用于管理组件实例和状态更新:
import { useRef, useEffect } from \'react\';import type { MutableRefObject } from \'react\';import type { DescriptionProps, DescInstance } from \'./typing\';export function useDescription(initialProps?: Partial) { const descRef = useRef(null); const isLoaded = useRef(false); const timerRef = useRef(null); const register = (instance: DescInstance | null) => { if (instance) { descRef.current = instance; isLoaded.current = true; if (initialProps) instance.setDescProps(initialProps); } else { descRef.current = null; isLoaded.current = false; if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } } }; const setDescProps = (props: Partial) => { if (!isLoaded.current) return; if (descRef.current) { descRef.current.setDescProps(props); } else if (!timerRef.current) { timerRef.current = setTimeout(() => { setDescProps(props); timerRef.current = null; }, 100); } }; useEffect(() => { return () => { if (timerRef.current) clearTimeout(timerRef.current); isLoaded.current = false; descRef.current = null; }; }, []); return { register, setDescProps, descRef: descRef as MutableRefObject };}
4. 组件导出(index.ts)
规范组件导出:
import Description from \'./src/Description.tsx\';export { Description }
功能特性
-
动态配置:通过 schema 定义描述项,支持自定义标签、内容、样式
-
数据驱动:通过 data 属性动态渲染内容
-
条件渲染:支持 show 函数控制描述项显示/隐藏
-
自定义渲染:支持 render 函数自定义内容展示
-
实例方法:通过 useDescription hook 获取实例,调用 setDescProps 动态更新
-
类型安全:完善的 TypeScript 类型定义
使用示例
import { Description } from \'./components/Descrption\';import { useDescription } from \'./components/Descrption/src/useDescription\';const App = () => { const { register } = useDescription({ schema: detailSchema, data, title: \"基本信息\", column: 2, labelStyle: { minWidth: \"250px\" }, contentStyle: { minWidth: \"300px\" }, }); const schema = [ { label: \'姓名\', field: \'name\', labelMinWidth: 100 }, { label: \'年龄\', field: \'age\' }, { label: \'邮箱\', field: \'email\', render: (value) => {value} }, { label: \'地址\', field: \'address\', span: 2, show: (data) => data.address }, ]; const data = { name: \'张三\', age: 28, email: \'zhangsan@example.com\', address: \'北京市海淀区\' }; return ( );};
总结
本文介绍了如何基于 Ant Design 和 React,参考 Vben Admin 的设计思想,封装一个功能完善的描述列表组件。通过 TypeScript 类型定义确保类型安全,使用 React hooks 管理状态和实例,支持动态配置和自定义渲染,满足各种复杂场景的需求。这种组件封装方式不仅提高了代码复用性,也便于维护和扩展,是现代前端开发中的最佳实践之一。