'f'
mh-two-thousand-and-two
2024-04-12 26f2711ef9461961fb953e2b497bd314ef95e345
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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]))
      }
    })
  }
}