
Ant Design Empty 语义化结构定制classNames 与 styles 对象/函数用法全解析【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-designEmpty空状态组件是业务页面中「暂无数据」场景的标配。antd v5.23.0 起Empty 引入了「语义化结构Semantic DOM」定制能力通过classNames与styles两个属性并支持「对象」与「函数」两种写法即可对根节点、图片、描述、底部操作区分别做样式定制。本文以仓库中 style-class 示例 及其配套 style-class.md 说明文档为主体结合组件源码与测试用例完整讲解这套定制 API 的结构划分、两种写法、底层合并原理与可验证的测试行为。Empty 的语义化结构四个可定制节点在动手写样式前先明确「往哪写」。查看 Empty 组件实现 中定义的EmptySemanticTypeEmpty 的语义化结构一共包含四个节点export type EmptySemanticType { classNames?: { root?: string; image?: string; description?: string; footer?: string; }; styles?: { root?: React.CSSProperties; image?: React.CSSProperties; description?: React.CSSProperties; footer?: React.CSSProperties; }; };这四个节点对应的实际 DOM 及默认 class 前缀默认prefixCls为ant-empty如下与渲染代码一一对应语义化 key对应元素渲染位置说明来自 Semantic DOM 交互预览root最外层容器div.ant-empty根元素控制文本对齐、字体、行高与整体布局image图片容器div.ant-empty-image图片节点控制高度、透明度、边距与图片样式description描述div.ant-empty-description描述节点控制描述文案颜色等footer底部操作区div.ant-empty-footerfooter 节点控制与描述的上边距以及操作按钮如children传入的 Button同时注意两点容易忽略的实现细节当image使用内置的Empty.PRESENTED_IMAGE_SIMPLE简单版小图时根元素会额外追加ant-empty-normalclass见 className 拼接逻辑可据此针对性区分默认图与简单图的样式。旧的imageStyle属性已标记为deprecated组件会在开发环境输出imageStyle→styles.image的废弃警告见 deprecated 检测新代码请统一走styles.image。对象写法静态为每个语义节点单独定制在 style-class.tsx 示例中stylesObject使用「对象」写法为不同节点一次性注入行内样式const stylesObject: EmptyProps[styles] { root: { backgroundColor: #f5f5f5, borderRadius: 8px }, image: { filter: grayscale(100%) }, description: { color: #1890ff, fontWeight: bold }, footer: { marginTop: 16px }, };每个 key 对应上文四个语义节点之一value 是标准的React.CSSPropertiesroot的效果会落到根div.ant-empty的style上image/description/footer同理styles是行内样式天然具备最高优先级适合不需要抽离成样式文件的小范围调整。classNames的对象写法则用于挂自定义 class便于结合 CSS Modules、Tailwind 或普通全局样式表示例中先借助antd-style的createStaticStyles生成带css片段的静态 class再挂载到根节点import { createStaticStyles } from antd-style; const classNames createStaticStyles(({ css }) ({ root: css border: 1px dashed #ccc; padding: 16px; , })); // 组件内使用 const emptyClassNames: EmptyProps[classNames] { root: classNames.root, }; Empty {...emptySharedProps} descriptionObject styles classNames{emptyClassNames} styles{stylesObject} /说明示例中使用的createStaticStyles来自antd-style已列入仓库 package.json 依赖用于把 CSS-in-JS 片断编译为一份可复用的静态 class若你的项目不使用antd-style直接在classNames.root传入自己定义的 className 字符串即可API 语义完全一致。示例还通过emptySharedProps复用了两个渲染实例的公共配置——image采用Empty.PRESENTED_IMAGE_SIMPLEchildren传入主操作按钮Create Now——这正好演示了「语义化定制」与「内容定制」可以正交组合。函数写法根据 props 动态返回样式对象写法的局限是无法感知当前组件的实际 props。因此classNames/styles都支持「函数」写法函数接收{ props }参数即当前 Empty 接收到的完整 props返回同样结构的对象。示例中的stylesFn根据是否有description动态切换配色const stylesFn: EmptyProps[styles] ({ props }): GetPropEmptyProps, styles, Return { if (props.description) { return { root: { backgroundColor: #e6f7ff, border: 1px solid #91d5ff }, description: { color: #1890ff, fontWeight: bold }, image: { filter: hue-rotate(180deg) }, }; } return {}; };写法要点入参为{ props }props即传给Empty的全部属性description、image、children等皆可参与判断返回值类型与对象写法相同且可以不写全所有节点上例无description时返回空对象即「不加额外样式」类型上可用EmptyProps[styles]标注若需精确定位函数形式返回值可用GetPropEmptyProps, styles, Return仓库示例即采用此写法这也是GetProp泛型工具在 v5 语义化 API 中的典型用法。在组件内函数写法与对象写法可混用classNames用对象挂静态 classstyles用函数动态行内样式如示例所示。底层原理多来源合并与优先级无论对象还是函数最终都会汇入统一合并逻辑。Empty 内部调用了通用 Hook useMergeSemanticconst [mergedClassNames, mergedStyles] useMergeSemantic EmptySemanticAllType[classNames], EmptySemanticAllType[styles], EmptyProps ([contextClassNames, classNames], [contextStyles, contextStyleRoot, styles, styleRoot], { props, });从这段实现可以得出四个关键结论函数先求值再合并resolveStyleOrClass会对函数形式执行value({ props })得到结果对象后再参与合并实现代码。支持来自ConfigProvider的全局配置contextClassNames/contextStyles/contextStyle通过 useComponentConfig(empty) 取自 ConfigProvider 的empty组件级配置因此可在应用根部统一定义全局 Empty 风格再被组件局部配置覆盖。合并顺序决定优先级styles 按传入顺序用{ ...acc, ...cur }浅合并后传入的键值覆盖前者mergeStylesclassNames 则由clsx拼接共存。行内 style 与全局 style 的差异被妥善处理style/ 上下文style会被useSemanticRootStyle包裹为{ root: style }再参与合并保证root节点的styles.root覆盖关系符合「组件内联 ConfigProvider」的直觉。「root 样式优先级」这一点有专门测试背书semantic.test.tsx 中的 root style priority 用例 通过ConfigProvider empty{{ styles, style }}与组件自身styles/style组合断言根节点最终样式可看作该优先级的可执行规范。测试用例佐证函数化定制的两种形态仓库中 semantic.test.tsx 对本示例所展示的两种写法做了直接验证函数化动态切换classNames/styles以函数传入时测试断言带description时根节点挂上.empty-with-desc且背景为红移除description后 rerender 切换为.empty-no-desc且背景为蓝——证明函数每次渲染都会基于最新 props 重新求值对象形式生效{ root: empty-custom, image: empty-image-custom }与{ root: {...}, image: {...} }会被正确写到对应语义节点通过container.querySelector(.empty-custom)与.empty-image-custom断言。同时API 文档 中classNames/styles的类型定义也与此一一对应RecordSemanticDOM, string | (info: { props }) RecordSemanticDOM, string // classNames RecordSemanticDOM, CSSProperties | (info: { props }) RecordSemanticDOM, CSSProperties // styles两者自5.23.0版本引入并且均可通过 ConfigProvider 的组件级全局配置 下发实现全站空状态风格统一。实践建议静态需求用对象条件需求用函数仅需固定美化时对象写法更清晰需要「有/无描述」「是否简单图」「是否 RTL」等条件分支时用函数写法基于props判断避免在渲染外手工计算。class 与 style 分工涉及媒体查询、伪类、动画等复杂样式优先走classNames挂类简单覆盖用styles行内样式更直接。注意替换废弃属性若代码中仍在使用imageStyle请迁移为styles.image开发环境会收到废弃提示。善用全局配置多页面共用的空状态外观建议收敛到ConfigProvider的empty组件配置中组件局部再按需微调避免重复样板。小结Empty 的classNames/styles语义化定制 API通过root、image、description、footer四个结构节点把原本「要么不动、要么整体重写」的空状态组件拆成了可精确打击的样式面。对象与函数两种写法分别覆盖静态与动态场景而底层的 useMergeSemantic 统一了「组件局部 ConfigProvider 全局」的合并优先级并以测试用例固化了行为边界。需要实际体验完整渲染效果时可直接参考 style-class.tsx 运行示例。【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考