import observe from '../observer/observer' import Watcher from '../observer/watcher' import Computed from '../observer/computed' import { proxy } from '../util/util' import DD from '.' /** * 代理配置项 * @param dd */ export default function initState(dd: DD) { let opt = dd.$options // 观察并代理 data 属性中数据 if (opt.data) initData(dd) // 观察并代理 props 属性中数据 if (opt.props) initProp(dd) // 处理 watch 属性内容 if (opt.watch) initWatch(dd) // 处理 computed 属性内容 if (opt.computed) initComputed(dd) // 代理 methods 属性中方法 if (opt.methods) initMethod(dd) } function initData(dd: DD) { // let a = b = {} 的写法使得 a、b 指向同一个地址 let data = (dd._data = dd.$options.data ? dd.$options.data.call(dd) : {}) // 将 data 对象变成可监听结构 observe(data) for (let key in dd._data) { // 把 dd.data() 挂载在 dd,使得原来通过 dd.data().key 访问的数据,可以通过 dd.key 访问 proxy(dd, '_data', key) } } function initProp(dd: DD) { let props: any = (dd._props = {}) // 根据 props 中的 key 去 propsData 中取值 let propsData = dd.$options.propsData || {} for (let key in dd.$options.props) { let value = propsData[key] // console.log(dd.$options.props[key].type) if (!value) value = dd.$options.props[key].default props[key] = value } observe(props) for (let key in dd._props) { // 把 dd.props 挂载在 dd,使得原来通过 dd.props.key 访问的数据,可以通过 dd.key 访问 proxy(dd, '_props', key) // 监听父元素的属性,当父实例的属性变化时,更新子实例的该属性 // 这也是 prop 属性名需要和父实例 data 中属性名同名的原因 new Watcher(dd.$parent, key, (newValue: any) => { dd[key] = newValue }) } } function initWatch(dd: DD) { for (let key in dd.$options.watch) { let watch = new Watcher( dd, () => { return key.split('.').reduce((obj, name) => obj[name], dd) }, (newValue: any, oldValue: any) => { dd.$options.watch[key].forEach((fnc: Function) => fnc(newValue, oldValue) ) } ) dd._watchers.push(watch) } } function initComputed(dd: DD) { let computed: any = (dd._computed = {}) for (let key in dd.$options.computed) { computed[key] = new Computed(dd, key, dd.$options.computed[key]).value } observe(computed) for (let key in dd._computed) { // 把 dd.computed 挂载在 dd,使得原来通过 dd.computed.key 访问的数据,可以通过 dd.key 访问 proxy(dd, '_computed', key) } } function initMethod(dd: DD) { for (let key in dd.$options.methods) { dd[key] = dd.$options.methods[key].bind(dd) dd.$on(key, dd[key]) } }