import {
|
hasOwn,
|
isPlainObject
|
} from 'uni-shared'
|
|
import {
|
deepClone
|
} from './deep-clone'
|
|
const PROP_DEFAULT_VALUES = {
|
[String]: '',
|
[Number]: 0,
|
[Boolean]: false,
|
[Object]: null,
|
[Array]: [],
|
[null]: null
|
}
|
|
function getDefaultVal (propType) {
|
return PROP_DEFAULT_VALUES[propType]
|
}
|
|
function getPropertyVal (options) {
|
if (isPlainObject(options)) {
|
if (hasOwn(options, 'value')) {
|
return options.value
|
}
|
return getDefaultVal(options.type)
|
}
|
return getDefaultVal(options)
|
}
|
|
function getType (propOptions) {
|
return isPlainObject(propOptions) ? propOptions.type : propOptions
|
}
|
|
function validateProp (key, propsOptions, propsData, vm) {
|
let value = propsData[key]
|
if (value !== undefined) {
|
const propOptions = propsOptions[key]
|
const type = getType(propOptions)
|
value = formatVal(value, type)
|
const observer = propOptions && propOptions.observer
|
if (observer) {
|
// 初始化时,异步触发 observer,否则 observer 中无法访问 methods 或其他
|
setTimeout(function () {
|
observe(observer, vm, value)
|
}, 4)
|
}
|
return value
|
}
|
return getPropertyVal(propsOptions[key])
|
}
|
|
function formatVal (val, type) {
|
if (type === Boolean) {
|
return !!val
|
} else if (type === String) {
|
return String(val)
|
}
|
return val
|
}
|
|
function observe (observer, vm, newVal, oldVal) {
|
try {
|
if (typeof observer === 'function') {
|
observer.call(vm, newVal, oldVal)
|
} else if (typeof observer === 'string' &&
|
typeof vm[observer] === 'function'
|
) {
|
vm[observer](newVal, oldVal)
|
}
|
} catch (err) {
|
console.error(`execute observer ${observer} callback fail! err: ${err}`)
|
}
|
}
|
|
export function initProperties (vm, instanceData) {
|
const properties = vm.$options.mpOptions.properties
|
if (!properties) {
|
return
|
}
|
|
const propsData = deepClone(vm.$options.propsData) || {}
|
|
for (const key in properties) {
|
const observer = isPlainObject(properties[key]) ? properties[key].observer : false
|
let value = validateProp(key, properties, propsData, vm)
|
Object.defineProperty(instanceData, key, {
|
enumerable: true,
|
configurable: true,
|
get () {
|
return value
|
},
|
set (newVal) {
|
const oldVal = value
|
/* eslint-disable no-self-compare */
|
if (newVal === value || (newVal !== newVal && value !== value)) {
|
return
|
}
|
// TODO 临时方案,clone array
|
value = Array.isArray(newVal) ? newVal.slice(0) : newVal
|
if (observer) {
|
observe(observer, vm, newVal, oldVal)
|
}
|
// 触发渲染
|
vm.$forceUpdate()
|
}
|
})
|
}
|
}
|
|
export function updateProperties (vm) {
|
const properties = vm.$options.mpOptions && vm.$options.mpOptions.properties
|
const propsData = vm.$options.propsData
|
if (propsData && properties) {
|
Object.keys(properties).forEach(key => {
|
if (hasOwn(propsData, key)) {
|
vm[key] = formatVal(propsData[key], getType(properties[key]))
|
}
|
})
|
}
|
}
|