veui
Version:
Baidu Enterprise UI for Vue.js.
103 lines (94 loc) • 3.33 kB
JavaScript
import config, { configContext } from '../managers/config'
import { assign, pick, upperFirst } from 'lodash'
const { useProvider, useConsumer } = configContext
const internalKey = '__veui_config' // 直接固定保留吧,保证多次 useConfig 时可以复用统一注入逻辑
// useConfig('foo', ['bar']): 将 ConfigProvider 中的配置项 bar/bar.* 读取到 this.foo 中去
export default function useConfig (injectionKey, configPrefixes = ['']) {
configPrefixes = Array.isArray(configPrefixes)
? configPrefixes
: [configPrefixes]
const keys = Object.keys(config.getAll()).filter((k) =>
configPrefixes.some(
(cp) =>
cp === k ||
k.indexOf(`${cp}.`) === 0 || // `table.loadingOptions`
(cp === '' && k.indexOf('.') === -1) // global config like `theme`
)
)
return {
mixins: [useConsumer(internalKey)],
data () {
return {
// 实际组件依赖这个state,避免类似 datepicker.xxx 影响 Alert 组件
[injectionKey]: keys.reduce((acc, key) => {
acc[key] = undefined
return acc
}, {})
}
},
watch: {
[internalKey]: {
handler (newVal) {
// watch 合并策略是合并成数组
assign(this[injectionKey], pick(newVal, keys))
},
immediate: true
}
}
}
}
// useConfigurable('config', {
// namespace: 'uploader',
// props: [
// 'headers', // string | {prop: 'headers', computed: 'realHeaders'}
// 'requestMode'
// ]
// })
// 1. 先从 ConfigProvider 中读取配置项 uploader.headers、uploader.requestMode 到 this.config
// 2. props.headers 覆盖 ConfigProvider中 的 uploader.headers
// 3. this.realHeaders 是最终使用的值,realRequestMode也是如此
export function useConfigurable (injectionKey, configurable) {
// normalize
const realConfigurable = map(configurable, (conf) => {
let realConf = typeof conf === 'string' ? { namespace: conf } : conf
realConf.props = map(realConf.props, (prop) =>
typeof prop === 'string' ? { prop } : prop
)
return realConf
})
function override () {
return realConfigurable.reduce((acc, { namespace, props }) => {
return props.reduce((acc, { prop, computed }) => {
if (typeof this[prop] !== 'undefined') {
acc[namespace ? `${namespace}.${prop}` : prop] =
this[computed || `real${upperFirst(prop)}`]
}
return acc
}, acc)
}, {})
}
// generate computeds
const namespaces = realConfigurable.map((i) => i.namespace || '')
return {
mixins: [
useConfig(injectionKey, namespaces, override),
useProvider(internalKey, { override })
],
computed: realConfigurable.reduce((acc, { namespace, props }) => {
return props.reduce((acc, { prop, computed }) => {
acc[computed || `real${upperFirst(prop)}`] = function () {
return typeof this[prop] === 'undefined'
? this[injectionKey][namespace ? `${namespace}.${prop}` : prop]
: this[prop]
}
return acc
}, acc)
}, {})
}
}
function map (target, iterator) {
// 不用 _.map 的原因是 target 不是数组时不要当成对象的 map
return (Array.isArray(target) ? target : target == null ? [] : [target]).map(
iterator
)
}