wot-design-uni useConfigProvider 组合式函数:在 JS 逻辑中注入全局主题配置的实战指南
wot-design-uni useConfigProvider 组合式函数:在 JS 逻辑中注入全局主题配置的实战指南
useConfigProvider 是 wot-design-uni 提供的一个组合式函数(Composable),用于在纯 JS 逻辑中注入全局配置(如主题变量),从而解决微信小程序等环境下组件渲染机制限制导致的 ConfigProvider 配置无法向下传递的问题。本文将从背景问题、基础用法、源码实现原理、类型系统、项目实战与测试验证六个层面,带你完整掌握该 API 的使用与底层机制。
一、为什么需要 useConfigProvider:依赖注入在小程序端的天然限制
在 Web 端,ConfigProvider 组件通过 Vue 的依赖注入(provide/inject)机制向下传递主题配置,子组件可以轻松获取父级配置。但在微信小程序等环境中,存在两类典型场景会导致这种传递失效:
- 原生插槽作用域隔离:小程序端组件渲染机制与 Web 不同,渲染在原生插槽中的节点可能无法访问插槽出口外层
ConfigProvider组件的注入上下文,导致深度嵌套或跨组件树的组件拿不到父级主题配置。 root-portal节点搬移:使用wd-root-portal将节点渲染到根节点(如 H5 端的teleport、小程序端的root-portal、App 端的 renderjs)后,节点脱离了原有的组件树,注入上下文随之丢失。
正如 ConfigProvider 全局配置 文档所述,useConfigProvider 的核心价值在于:允许开发者直接在 JS 逻辑中注入配置,确保深层嵌套或跨组件树的组件也能正确获取主题样式。它需要与 ConfigProvider 组件配合使用——先用 ConfigProvider 组件包裹你的组件,再在逻辑层调用 useConfigProvider。
二、基础用法:reactive 与 ref 两种注入方式
useConfigProvider 接收一个包含 themeVars 的对象参数,themeVars 既可以是普通响应式对象(reactive),也可以是 ref 包装的响应式引用:
import { useConfigProvider } from '@/uni_modules/wot-design-uni'
import { reactive, ref } from 'vue'
// 使用 reactive
const themeVars = reactive({
colorTheme: 'red',
buttonPrimaryBgColor: '#07c160'
})
useConfigProvider({ themeVars })
// 或者使用 ref
const themeVarsRef = ref({
colorTheme: 'blue'
})
useConfigProvider({ themeVars: themeVarsRef })
两种方式均支持响应式更新:当你后续修改 themeVars 或 themeVarsRef.value 中的属性值时,注入的主题样式会自动重新计算并同步到下游组件。
三、源码实现原理:provide/inject + CSS 变量映射
useConfigProvider 的实现位于 useConfigProvider.ts,整体逻辑非常精简,核心包含三部分:
1. 注入 Key 的定义
export const USE_CONFIG_PROVIDER_KEY = '__CONFIG_PROVIDER__'
该 Key 是组件与组合式函数之间通信的桥梁。wd-config-provider 与 wd-root-portal 组件内部都会通过 inject(USE_CONFIG_PROVIDER_KEY, None) 消费这份注入:
- wd-config-provider.vue 在
themeStyle计算属性中优先读取hooksProvider.themeStyle.value,仅在未注入时回退到自身props.themeVars; - wd-root-portal.vue 同样优先读取注入的
themeStyle,再回退到父级ConfigProvider的配置。
这意味着,只要你在逻辑层调用了 useConfigProvider,包裹在这些组件之下的所有 Wot 组件都能拿到你注入的主题变量,无需依赖组件树中的注入链。
2. 主题变量到 CSS 变量的映射
export const kebabCase = (str: string): string => {
str = str.replace(str.charAt(0), str.charAt(0).toLocaleLowerCase())
return str.replace(/([a-z])([A-Z])/g, (_, p1, p2) => p1 + '-' + p2.toLowerCase())
}
export const mapThemeVarsToCSSVars = (themeVars: Record<string, string>) => {
if (!themeVars) return
const cssVars: Record<string, string> = {}
Object.keys(themeVars).forEach((key) => {
cssVars[`--wot-${kebabCase(key)}`] = themeVars[key]
})
return cssVars
}
mapThemeVarsToCSSVars 的映射规则非常直观:
- 将驼峰命名的变量名转成 kebab-case(短横线命名),并统一加上
--wot-前缀; - 例如文档中的
colorTheme会转换为--wot-color-theme,buttonPrimaryBgColor会转换为--wot-button-primary-bg-color。
这正是 wot-design-uni 全部组件样式所依赖的 CSS 变量体系,与 ConfigProvider 主题定制 中"在 :root / page 节点上覆写 --wot-* 变量"的机制完全同源。
3. 注入响应式主题样式
export function useConfigProvider({ themeVars }: { themeVars: ConfigProviderThemeVars | Ref<ConfigProviderThemeVars> }) {
const themeStyle = computed(() => {
const styleObj = mapThemeVarsToCSSVars(unref(themeVars))
return styleObj ? `${objToStyle(styleObj)}` : ''
})
provide(USE_CONFIG_PROVIDER_KEY, {
themeStyle
})
}
实现要点:
- 通过
unref(themeVars)统一解包reactive对象与ref引用,因此两种传参方式行为一致; - 用
computed包裹,保证主题变量变化时样式字符串自动更新; - 最终通过 objToStyle(位于
common/util.ts)将{ '--wot-color-theme': 'red' }形式的样式对象序列化为--wot-color-theme:red;这样的内联样式字符串,注入给下游组件使用。
四、类型系统:ConfigProviderThemeVars 全量主题变量
useConfigProvider 的参数类型为 ConfigProviderThemeVars | Ref<ConfigProviderThemeVars>。该类型定义在 types.ts,由 baseThemeVars 与数十个组件级主题变量类型交叉合并而成,覆盖了组件库中几乎全部组件。
1. 基础主题变量(baseThemeVars)
baseThemeVars 定义了一套全局基础色板与排版变量,例如:
| 变量 | 说明 |
|---|---|
colorTheme |
主题色 |
colorSuccess / colorWarning / colorDanger |
成功 / 警告 / 危险色 |
colorBg |
背景色、禁用填充色 |
darkBackground ~ darkBackground7 |
深色模式下的多级背景色 |
colorTitle / colorContent / colorSecondary / colorAid |
标题 / 正文 / 次要 / 辅助文字色 |
fsBig ~ fsAid |
大型标题到辅助文字的字号 |
fwMedium / fwSemibold |
字重 500 / 600 |
sizeSidePadding |
屏幕两边留白 padding |
2. 组件级主题变量
类型系统为每个组件提供了专属的变量分组,例如:
buttonThemeVars:buttonPrimaryBgColor、buttonPrimaryColor、buttonSmallHeight、buttonMediumRadius等(types.ts);cellThemeVars:cellPadding、cellTitleFs、cellLabelColor等;inputThemeVars、tabsThemeVars、toastThemeVars、navbarThemeVars等数十个分组。
因此,在 TypeScript 项目中定义 themeVars 时,建议直接使用导出的 ConfigProviderThemeVars 类型以获得完整的类型提示:
import type { ConfigProviderThemeVars } from '@/uni_modules/wot-design-uni'
const themeVars: ConfigProviderThemeVars = {
colorTheme: 'red',
buttonPrimaryBgColor: '#07c160'
}
该类型已通过 index.ts 从组件库入口导出。
五、项目实战:page-wraper 中的动态主题注入
在本仓库的示例应用里,useConfigProvider 被真实用于页面包装组件。参见 page-wraper.vue:
const themeVars = computed<ConfigProviderThemeVars>(() => {
return isRed.value ? { colorTheme: 'red' } : {}
})
useConfigProvider({ themeVars })
这是一个非常有代表性的实践模式:
- 将
themeVars声明为computed<ConfigProviderThemeVars>,根据页面状态(如某个"红色主题"开关isRed)动态返回不同的主题变量; - 直接调用
useConfigProvider({ themeVars })注入; - 当
isRed状态变化时,注入的--wot-color-themeCSS 变量随之更新,页面内所有 Wot 组件的主题色同步切换。
这种"逻辑层驱动主题"的写法,配合 wd-config-provider 组件的 theme 属性(light / dark 深色模式切换),可以组合出灵活的全局主题方案:组件树负责结构渲染,useConfigProvider 负责在任意 JS 位置注入样式配置,两者各司其职。
六、测试验证:三种传参方式的响应式行为
仓库的单元测试 useConfigProvider.test.ts 使用 vitest + @vue/test-utils 对组合式函数的行为做了完整验证:
- 普通对象:
useConfigProvider({ themeVars: { colorTheme: 'red' } })后,子组件通过inject(USE_CONFIG_PROVIDER_KEY)能读取到--wot-color-theme:red样式字符串; - reactive 对象:修改
themeVars.colorTheme = 'blue'并await nextTick()后,注入的样式同步变为--wot-color-theme:blue,验证了响应式更新链路; - ref 引用:整体替换
themeVars.value = { colorTheme: 'green' }后,样式同样更新为绿色。
这三条用例从测试层面印证了 computed + unref 实现同时兼容"属性级更新"与"引用级替换"两类响应式变更场景,为生产使用提供了可靠性保障。
七、API 参数说明
| 参数 | 说明 | 类型 | 默认值 | 最低版本 |
|---|---|---|---|---|
| themeVars | 主题变量对象,支持响应式更新 | ConfigProviderThemeVars | Ref<ConfigProviderThemeVars> |
- | 1.14.0 |
注意:该 API 自 1.14.0 版本引入,使用时请确认组件库版本不低于此版本。
八、使用建议与注意事项
- 必须与
ConfigProvider组件配合:useConfigProvider注入的样式需要由wd-config-provider组件消费并应用到其子树,因此请确保你的组件被ConfigProvider包裹; - 优先在页面 / 应用顶层调用:注入是就近生效的,将
useConfigProvider放在页面根组件或App.ku.vue(配合虚拟根组件实现全局共享)等顶层位置,能最大化覆盖范围; - 善用 computed 实现动态主题:像
page-wraper一样用computed<ConfigProviderThemeVars>返回主题变量,即可实现运行时主题切换; - 类型安全:使用
ConfigProviderThemeVars类型约束themeVars,既能获得智能提示,也能避免拼写错误的变量名导致 CSS 变量失效; - 变量命名遵循驼峰:主题变量统一使用驼峰命名(如
buttonPrimaryBgColor),内部会自动映射为--wot-前缀的 kebab-case CSS 变量,不要直接写--wot-button-primary-bg-color形式。
通过 useConfigProvider,你可以在微信小程序、H5、App 等所有端上,以统一、可靠的方式将全局主题配置注入到任意层级的组件中,彻底绕开小程序端依赖注入与原生插槽隔离带来的上下文丢失问题。