官方文档:Config Provider 全局配置
在组件库的设计中,最常见的全局配置是 z-index
和 size
z-index
:统一管理弹出层(dialog, message, loading)等组件的层级。size
:统一管理表单元素大小。这些都属于全局配置项,可以Config Provider
全局配置来实现。
全局配置项有2种引入方式。但都是调用同一个全局配置函数 provideGlobalConfig
实现的,后面会详细介绍。
1,完整引入
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus, { size: 'small', zIndex: 3000 })
相当于在element-plus
的install
方法中,调用了provideGlobalConfig()
const install = (app, options) => {
// ...
if (options) provideGlobalConfig(options, app, true)
// ...
}
2,按需引入
<template>
<el-config-provider :size="size" :z-index="zIndex">
<app />
el-config-provider>
template>
<script>
import { defineComponent } from 'vue'
import { ElConfigProvider } from 'element-plus'
export default defineComponent({
components: {
ElConfigProvider,
},
setup() {
return {
zIndex: 3000,
size: 'small',
}
},
})
script>
el-config-provider
组件中,调用了provideGlobalConfig()
el-config-provider
的子组件传入,也相当于全局引入。
el-config-provider
组件,传入指定的配置项props
,在子组件中生效。
现在明确了:
install
方法调用provideGlobalConfig()
,el-config-provider
组件调用provideGlobalConfig()
,install
方法没什么好说的,所以先介绍下el-config-provider
组件,再来详细介绍provideGlobalConfig()
。
组件路径:
packages\components\config-provider\src\config-provider.ts
代码稍微做了简化。
import { defineComponent, renderSlot } from 'vue'
import { provideGlobalConfig } from './hooks/use-global-config'
const ConfigProvider = defineComponent({
name: 'ElConfigProvider',
// locale | size | zIndex | namespace | button | message 等
props: configProviderProps,
setup(props, { slots }) {
const config = provideGlobalConfig(props)
return () => renderSlot(slots, 'default', { config: config?.value })
},
})
export default ConfigProvider
renderSlot()
和h('div', xxx)
一样,会返回 VNode,但参数不一致。
可以在
setup()
中返回渲染函数来创建组件。
export declare function renderSlot(
slots: Slots,
name: string,
props?: Data,
fallback?: () => VNodeArrayChildren,
noSlotted?: boolean
): VNode;
主要介绍前3个参数:
带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 slot 出口会隐式地命名为“default”
所以 renderSlot(slots, 'default', { config: config?.value })
定义的是默认插槽。
结合以上,Config Provider
组件如果使用 template 定义,大致如下
<template>
<div>
<slot :config="config">slot>
div>
template>
<script lang="ts" setup>
const config = provideGlobalConfig(props)
script>
关于传给父组件的 props 的举例:
<div>
<slot :text="greetingMessage" :count="1">slot>
div>
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
MyComponent>
先介绍依赖的变量和函数
1,定义全局配置对象globalConfig
// 全局配置对象
const globalConfig = ref()
// 全局配置依赖注入 provide/inject 的 key
const configProviderContextKey = Symbol()
2,获取全局配置的 hook 函数
useGlobalConfig()
直接调用,获取全局配置useGlobalConfig('namespace', 'el')
传参调用,获取指定的全局配置import { getCurrentInstance } from 'vue'
function useGlobalConfig(key, defaultValue = undefined) {
const config = getCurrentInstance() ? inject(configProviderContextKey, globalConfig) : globalConfig
if (key) {
return computed(() => config.value?.[key] ?? defaultValue)
} else {
return config
}
}
3,合并(新旧)全局配置
// 新值 b 会覆盖旧值 a
const mergeConfig = (a, b) => {
const keys = [...new Set([...Object.keys(a), ...Object.keys(b)])]
const obj = {}
for (const key of keys) {
obj[key] = b[key] ?? a[key]
}
return obj
}
4,provideGlobalConfig
有3个参数,是因为有2种调用方式。
el-config-provider
组件调用时,只会传入全局配置参数config
app
,此时参数 global = true
,会对全局配置对象globalConfig
赋值。import { getCurrentInstance } from 'vue'
const provideGlobalConfig = (config, app, global = false) => {
// 在 setup() 或