vimo-dt
Version:
A Vue2.x UI Project For Mobile & HyBrid
329 lines (303 loc) • 10.5 kB
JavaScript
/**
* @class Config
* @classdesc **App应用级别**的配置类
*
*
* ### 说明
*
* Config初始化的实例能配置整个App, 也能根据使用的平台单独配置而互不影响. 另外, 配置信息也能自定义, 比如说存放合成变量.
*
* 获取过一次的配置会被缓存在实例中, 便于后续快速使用. 此外, 在业务中可用过this.$config获取已定义的变量, 比如:
*
* ```
* this.$config.get('mode') => 'ios/md'
* ```
*
* config的初始化Vimo安装的时候就搞定了, 实例会在`window.VM.config`中也留一份, 便于外部业务能访问到.
*
* ### 关于配置的优先级
*
* 也可以在url中传入配置参数, 通过url配置App的前后缀, 例如 http://xx.xx.com?vmMode=ios
* 则参数mode的值为ios, 改变mode并无法改变真实的mode环境, 因为平台验证有自己的isMatch方法, 切记!!
*
* #### 优先级
*
* ** url获取配置信息(URL) > 用户自定义配置(Config) > 平台默认配置(Platform) **
*
* ```
* 第一优先级(URL):
* http://xx.xx.com?vmMode=ios
*
* 第二优先级(Config):
* 在src/config/app-configs.js中的platforms字段中设置
* export default {
* domain: '',
* platforms: {
* ios: {
* mode: 'md'
* }
* }
* }
*
* 第三优先级(Config):
* 在src/config/app-configs.js中根属性中设置
* export default {
* domain: '',
* mode: 'ios'
* }
*
* 第四优先级(Platform):
* 如果当前的_platforms = ['mobile','ios','wechat']
* 在src/config/platform-configs.js中设置
* export default {
* wechat: {
* settings: {
* mode: 'md'
* }
* }
* }
*
* 第五优先级(Platform):
* 如果当前的_platforms = ['mobile','ios','wechat']
* 在src/config/platform-configs.js中设置
* export default {
* ios: {
* settings: {
* mode: 'md'
* }
* }
* }
* ```
*
* #### 可配置的参数有
*
* 参数 / params | 默认值 / IOS | 默认值 / Android | 描述 / Description
* -----------------|----------------|-----------------|------------------
* mode | ios | md | 模式
* hideNavBar | false | false | 是否隐藏navbar
* toolbarMinHeight | 44 | 56 | toolbar的最小高度
* iconMode | ios | md | icon的模式
* menuType | reveal | overlay | menu展示方式
* backButtonText | '' | '' | 后退按钮文字
* backButtonIcon | '' | '' | 后退按钮图标icon
* spinner | ios | crescent | 菊花图配型
* tabsHighlight | false | true | tab是否有下划线
* tabsPlacement | bottom | bottom | tab的放置位置
* pageTransition | ios-transition | zoom-transition | 转场动画
* showIndicatorWhenPageChange | true | true | 转场是否显示Indicator
**/
const isFunction = val => typeof val === 'function'
const isDefined = val => typeof val !== 'undefined'
const isObject = val => typeof val === 'object'
const isArray = Array.isArray
// 通过url配置App的前后缀, 例如htttp://xx.xx.com?vmMode=ios
const URL_CONFIG_PREFIX = 'vm'
export class Config {
constructor () {
/**
* @private
* */
this._cache = {} // cache 获取配置的缓存对象, 可用的config只有调用的时候才知道!
this._settings = {} // setting/store/superlative 最高级配置 用户在初始化时自己的配置config
this.plt = null // Platform 当前平台的实例
}
/**
* 初始化配置信息, 传入用户自定义的配置, 生效的优先级如下:
* ```
* config.platforms.ios.key > config.key
* ```
* @param {any} config - 初始化的config配置信息, 用户自定义的配置(最高级配置)
* @param {Platform} [plt] - 当前平台的platform实例, 可选
* @private
*/
init (config, plt) {
this._settings =
config && isObject(config) && !isArray(config) ? config : {}
this.plt = plt
}
/**
* 获取配置信息
* @param {string} [key] - 查找的key
* @param {any} [fallbackValue] - 第二选择
* @return {String}
*/
get (key, fallbackValue = null) {
const platform = this.plt
// 如果已缓存则取缓存值
if (!isDefined(this._cache[key])) {
if (!isDefined(key)) {
// eslint-disable-next-line no-throw-literal
throw new Error('config key is not defined')
}
// 如果查询的值之前查过, 则使用缓存值
// 如果之前没查过, 则查询配置, 查询顺序如下:
// url_params > config > plt._register[platform]
let userPlatformValue // config[platforms][platform][key]
let userDefaultValue = this._settings[key] // config[key]
let platformValue // this.plt._registry[platformName].setting[key]
let configObj = null
if (platform) {
// 如果配置信息是定义在queryParam中的话, 读取并注册到_c中, 查询的关键字key是小写
var queryStringValue = platform.getQueryParam(URL_CONFIG_PREFIX + key)
if (isDefined(queryStringValue)) {
if (queryStringValue === 'true') {
this._cache[key] = true
} else if (queryStringValue === 'false') {
this._cache[key] = false
} else {
this._cache[key] = queryStringValue
}
return this._cache[key]
}
// 获取激活的platform, 此时已经知道层级关系, 最后一个为最重要的, 例如: ['mobile','ios','wechat']
var activePlatformKeys = platform.platforms()
// 循环查询每一个激活的平台, 在config.platforms中定义的配置
for (var i = 0, ilen = activePlatformKeys.length; i < ilen; i++) {
if (this._settings.platforms) {
configObj = this._settings.platforms[activePlatformKeys[i]]
if (configObj) {
if (isDefined(configObj[key])) {
userPlatformValue = configObj[key]
}
}
}
// 获取在平台上的配置(platform-registry.js)
// 在[mode].setting中
configObj = platform.getPlatformConfig(activePlatformKeys[i])
if (configObj && configObj.settings) {
if (isDefined(configObj.settings[key])) {
// found a setting for this platform
platformValue = configObj.settings[key]
}
}
}
}
// 缓存查询的的结果
// 返回优先级: 用户自在config.platforms中定义 > 用户在config中定义 > platform中定义
// eg: config[platforms][platformName][key] > config[key] > this.plt._registry[platformName].setting[key]
this._cache[key] = isDefined(userPlatformValue)
? userPlatformValue
: isDefined(userDefaultValue)
? userDefaultValue
: isDefined(platformValue) ? platformValue : null
}
var rtnVal = this._cache[key]
// 如果返回函数则导入platform执行
if (isFunction(rtnVal)) {
rtnVal = rtnVal(platform)
}
return rtnVal !== null ? rtnVal : fallbackValue
}
/**
* 和get()方法类似, 不过只返回boolean类型, 比如"true"返回true
* @param {string} [key] - key值
* @param {boolean} [fallbackValue] - 备选值
* value was `null`. Fallback value defaults to `false`.
* @return {Boolean}
*/
getBoolean (key, fallbackValue = false) {
const val = this.get(key)
if (val === null) {
return fallbackValue
}
if (typeof val === 'string') {
return val === 'true'
}
return !!val
}
/**
* 和get()方法类似, 不过只返回number类型
* @param {string} [key] - key值
* @param {number} [fallbackValue] - 备选值
* value turned out to be `NaN`. Fallback value defaults to `NaN`.
* @return {Number}
*/
getNumber (key, fallbackValue = NaN) {
const val = parseFloat(this.get(key))
return isNaN(val) ? fallbackValue : val
}
/**
* 修改config中定义的键值对, 可针对平台单独设置.
* @param {string} [platform] - 平台类型, 可以是(either 'ios' or 'android'). 如果不填将对所有平台生效.
* @param {string} [key] - key值
* @param {string} [value] - 设置的值
*
* @example
* set('key', 'value') = set key/value pair
* set('ios', 'key', 'value') = set key/value pair for platform
*
* @return {this}
*/
set (...args) {
const arg0 = args[0]
const arg1 = args[1]
switch (args.length) {
case 2:
// set('key', 'value') = set key/value pair
// arg1 = value
this._settings[arg0] = arg1
delete this._cache[arg0] // clear cache
break
case 3:
// set('ios', 'key', 'value') = set key/value pair for platform
// arg0 = platform
// arg1 = key
// arg2 = value
this._settings.platforms = this._settings.platforms || {}
this._settings.platforms[arg0] = this._settings.platforms[arg0] || {}
this._settings.platforms[arg0][arg1] = args[2]
delete this._cache[arg1] // clear cache
break
}
return this
}
/**
* 全部重新设置
* 1. 如果不传入参数则为获取_s的数据,
* 2. 如果传递`settings({...})`, 则设置_s的值, 同时清空_c
* 3. 如果传递`settings('ios', {...})`, 则清除_s.platforms['ios']下的值并设置新值, 同时清空_c
*
* @param {*} arg0 - 参数0
* @param {*} arg1 - 参数1
*
* @example
* settings()
* settings({...})
* settings('ios', {...})
*/
settings (arg0, arg1) {
switch (arguments.length) {
case 0:
return this._settings
case 1:
// settings({...})
this._settings = arg0
this._cache = {} // clear cache
break
case 2:
// settings('ios', {...})
this._settings.platforms = this._settings.platforms || {}
this._settings.platforms[arg0] = arg1
this._cache = {} // clear cache
break
}
return this
}
/**
* 获取缓存配置
* @return {object}
* */
cache () {
return this._cache
}
}
/**
* @function setupConfig
* @description Config类实例化
* @private
* */
export function setupConfig (config = {}, plt = {}) {
const c = new Config()
c.init(config, plt)
return c
}