Refine v5 + Ant Design 主题定制完全指南:从 RefineThemes 到深色模式与 Design Token 实践
2026/9/13 18:41:11 网站建设 项目流程

Refine v5 + Ant Design 主题定制完全指南:从 RefineThemes 到深色模式与 Design Token 实践

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

本指南以 documentation/docs/ui-integrations/ant-design/theming/index.md 为核心骨架,结合仓库内@refinedev/antd包的源码实现与可运行示例展开。你将掌握基于 Ant Design Design Token 的主题定制原理、RefineThemes预设主题的使用、ConfigProvider覆盖主题、预置算法(明暗/紧凑模式)切换,以及让通知组件正确跟随主题上下文的useNotificationProvider接入方式。

主题的原子单位:Design Token 与 Refine v5

Ant Design 允许通过定制 Design Token 来满足业务或品牌对 UI 多样性的需求,包括主色(primary color)、圆角(border radius)、边框颜色(border color)等。Design Token 是影响主题的最小元素——通过修改 Design Token,即可呈现出不同的主题样式或组件形态。在 Refine v5 中,这一能力被完整继承:无论使用ThemedLayout、表单还是表格,所有@refinedev/antd组件都会通过ConfigProvider的上下文消费这些 Token,从而保证整站风格统一。

这种"Token 驱动"的定制方式与 Refine 自身"UI 无关(headless)+ UI 适配包"的架构是一脉相承的:主题层完全交给 Ant Design 的 token 体系,Refine 只负责提供开箱即用的主题配置与上下文消费入口。

开箱即用的预设主题:RefineThemes

@refinedev/antd包导出了一组名为RefineThemes的预设主题,可以直接从包中导入使用:

const { Blue, Purple, Magenta, Red, Orange, Yellow } = RefineThemes;

在仓库中,RefineThemes的完整定义位于 packages/antd/src/definitions/themes/index.ts,它本质上是一个Record<ThemeNames, ThemeConfig>类型的对象,每个主题都是只包含token.colorPrimary的 Ant DesignThemeConfig

主题名colorPrimary适用场景参考
Blue#1677FF通用企业后台默认蓝
Purple#722ED1品牌强调、创意类产品
Magenta#EB2F96营销活动、女性向产品
Red#F5222D运营告警、强提示场景
Orange#FA541C电商促销、食品餐饮
Yellow#FAAD14提醒、注意级别提示
Green#52C41A成功反馈、金融数据

注意:原文档列出的解构示例只写了六个主题,但源码中实际上还包含Green。以 packages/antd/src/definitions/themes/index.ts 为准,完整解构应为const { Blue, Purple, Magenta, Red, Orange, Yellow, Green } = RefineThemes;

使用方式非常简单——将RefineThemes.Blue直接传给 Ant Design 的ConfigProvidertheme属性,再用ThemedLayout包裹内容即可:

import { Refine } from "@refinedev/core"; import { ThemedLayout, RefineThemes } from "@refinedev/antd"; import { ConfigProvider } from "antd"; const App: React.FC = () => { return ( <ConfigProvider theme={RefineThemes.Blue}> <Refine /* ... */> <ThemedLayout>{/* ... */}</ThemedLayout> </Refine> </ConfigProvider> ); };

仓库中 examples/theme-antd-demo/src/App.tsx 正是这样一个演示应用:它用一个ThemeSettings面板(见 examples/theme-antd-demo/src/components/theme-settings/index.tsx)动态遍历Object.keys(RefineThemes),渲染出一排以色块为背景的按钮,点击后调用onTokenColorClick(theme.token)把对应主题的token合并进当前ThemeConfig并回传给ConfigProvider,实现运行时即时换肤。对应的示例文档位于 documentation/docs/examples/themes/refine-themes-antd.md。

主题定制:ConfigProvider 是唯一入口

无论是使用ConfigProvider组件还是 Refine 提供的RefineThemes,其底层都是通过 Ant Design 的主题机制工作。如果你决定使用默认主题,则无需任何额外配置。

从源码结构看,@refinedev/antd的导出(见 packages/antd/src/index.tsx)将definitions/themes/index.js完整 re-export,因此RefineThemes与 Ant Design 的ThemeConfig类型体系完全互通——这意味着你可以把RefineThemes当作主题的"基础色板",在此之上做任意扩展。

覆盖与扩展:创建你自己的主题

你不仅可以覆盖或扩展默认主题,还可以完全创建自己的主题。Refine 官方的覆盖示例结合theme对象中的components(组件级 Token)与token(全局 Token)两层配置:

import { Refine } from "@refinedev/core"; import { ThemedLayout } from "@refinedev/antd"; import { ConfigProvider } from "antd"; const API_URL = "https://api.fake-rest.refine.dev"; const App: React.FC = () => { return ( <ConfigProvider theme={{ components: { Button: { borderRadius: 0, }, Typography: { colorTextHeading: "#1890ff", }, }, token: { colorPrimary: "#f0f", }, }} > <Refine /* ... */> <ThemedLayout>{/* ... */}</ThemedLayout> </Refine> </ConfigProvider> ); };

这里有两个值得注意的层级:

  • token(全局级)colorPrimary一旦设定,会向下传递给几乎所有组件,是影响面最大的 Token;
  • components(组件级):允许针对ButtonTypography等具体组件覆写其专属 Token,例如把按钮圆角改为0、把标题文字色改为指定色值。组件级配置的优先级高于全局 token。

在 examples/customization-theme-antd/src/App.tsx 中,官方示例将这些能力组合成了可运行的完整应用:theme对象内使用...RefineThemes.Blue展开预设主色,再叠加algorithmcomponentstoken覆盖,三层配置在同一个对象中并存且互不冲突。

预置算法:明暗与紧凑模式的切换利器

通过修改algorithm(算法)属性,可以快速生成不同风格的主题。Ant Design 5.x 默认提供三套预置算法:

  • theme.defaultAlgorithm:默认算法(浅色);
  • theme.darkAlgorithm:深色算法;
  • theme.compactAlgorithm:紧凑算法。

切换方式就是修改<ConfigProvider/>themealgorithm属性。algorithm本质上是一组 Token 变换函数,它接收默认 Token 并产出派生 Token(如深色模式下的背景色、文字色、边框色等),因此你完全可以把algorithm与自定义token叠加使用——例如"深色 + 品牌主色"的组合。

实战:为 Header 添加明暗切换开关

官方指南从"给Header组件加一个切换按钮"开始演示完整流程。先定义带theme状态与setTheme回调的Header组件:

import { Space, Button } from "antd"; interface HeaderProps { theme: "light" | "dark"; setTheme: (theme: "light" | "dark") => void; } const Header: FC<HeaderProps> = (props) => { return ( <Space direction="vertical" align="end" style={{ padding: "1rem", }} > <Button onClick={() => { props.setTheme(props.theme === "light" ? "dark" : "light"); }} icon={props.theme === "light" ? <IconMoonStars /> : <IconSun />} /> </Space> ); };

然后在根组件用useState管理当前主题,并根据状态在ConfigProvidertheme.algorithm中切换theme.defaultAlgorithmtheme.darkAlgorithm

import { Refine } from "@refinedev/core"; import { ThemedLayout } from "@refinedev/antd"; import { ConfigProvider, theme } from "antd"; import { Header } from "./Header"; const App: React.FC = () => { const [currentTheme, setCurrentTheme] = useState<"light" | "dark">("dark"); return ( <ConfigProvider theme={{ algorithm: currentTheme === "light" ? theme.defaultAlgorithm : theme.darkAlgorithm, }} > <Refine /* ... */> <ThemedLayout Header={Header}>{/* ... */}</ThemedLayout> </Refine> </ConfigProvider> ); };

注意这里的ThemedLayout Header={Header}是自定义主题切换的接入点。查看 packages/antd/src/components/themedLayout/index.tsx 可以看到,ThemedLayout接受HeaderSiderTitleFooterOffLayoutArea等插槽属性,Header ?? DefaultHeader的逻辑意味着传入自定义 Header 即可完全替换默认顶栏,其余布局结构保持不变。而默认的ThemedHeader(见 packages/antd/src/components/themedLayout/header/index.tsx)内部正是通过theme.useToken()读取当前token(如colorBgElevated)来渲染背景色——这解释了为什么"把ConfigProvider的 algorithm 一换,整个布局包括 Header 都会自动跟着变"。

完整的明暗切换示例同样落地在 examples/customization-theme-antd/src/App.tsx 中,其自定义 Header 实现见 examples/customization-theme-antd/src/components/Header/index.tsx。

主题感知的通知:useNotificationProvider

@refinedev/antd早期导出的notificationProvider已废弃,因为它默认无法消费当前的theme上下文。若希望Notification组件跟随主题(例如深色模式下通知弹出层也呈现深色样式),需要引入 antd 的App组件与@refinedev/antduseNotificationProvider

import { Refine } from "@refinedev/core"; import { ThemedLayout, useNotificationProvider } from "@refinedev/antd"; import { ConfigProvider, App as AntdApp } from "antd"; const API_URL = "https://api.fake-rest.refine.dev"; const App: React.FC = () => { return ( <ConfigProvider theme={RefineThemes.Blue}> <AntdApp> <Refine //... notificationProvider={useNotificationProvider} > <ThemedLayout>{/* ... */}</ThemedLayout> </Refine> </AntdApp> </ConfigProvider> ); };

其底层原理可以在 packages/antd/src/providers/notificationProvider/index.tsx 中看到完整实现:

export const useNotificationProvider = (): NotificationProvider => { const { notification: notificationFromContext } = App.useApp(); const notification = "open" in notificationFromContext ? notificationFromContext : staticNotification; // ... };

关键点在于:

  1. App.useApp()是从 antd 的App组件上下文取出的 notification 实例,它天然位于ConfigProvider之内,因此能消费当前主题上下文;
  2. 代码通过"open" in notificationFromContext做防御性判断:当应用没有包裹<AntdApp>时(此时App.useApp()返回空对象),自动回退到 antd 的静态notification方法,保证功能不中断;
  3. type === "progress"时,通知内容渲染为可撤销通知组件UndoableNotification(支持取消 mutation 并即时销毁通知),这在 Refine 的乐观更新/可撤销操作流程中尤为关键。

对应的单元测试 packages/antd/src/providers/notificationProvider/index.spec.tsx 明确覆盖了两种场景:未使用antdApp组件时(vi.spyOn(notification, "open")断言走静态 API)与使用App组件时(mockApp.useApp()返回值,断言走上下文实例),验证了 success/error/progress/close 等各类通知行为,可作为你接入时的行为参考。

布局级定制与完整示例

如果你需要定制@refinedev/antd提供的默认布局元素(如 Sider、Header 的默认内容),官方提供了专门的布局定制教程:documentation/docs/advanced-tutorials/custom-layout.md。

  • 主题预览示例:仓库中的 theme-antd-demo 演示了 7 种预设主题的实时切换(配合 ThemeSettings 面板),并叠加了明暗模式切换;
  • 主题覆盖示例:customization-theme-antd 演示了"RefineThemes 预设 + algorithm 切换 + 组件级覆盖"三合一的完整用法,与本指南各小节一一对应。

小结

在 Refine v5 + Ant Design 项目中,主题定制的完整路径可以归纳为一条清晰的主线:以 Design Token 为原子单位 → 用RefineThemes快速起步 → 通过ConfigProvidertoken/components/algorithm三层配置做精细覆盖 → 用ThemedLayout的插槽接入自定义 Header 实现交互式切换 → 用useNotificationProvider+<AntdApp>让通知等浮层也跟随主题。这些能力既有 Ant Design 生态的成熟机制支撑,也通过@refinedev/antd的源码实现(预设主题定义、布局组件、通知 Provider 及其测试)在仓库中得到了可验证的落地。

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询