import event from './event'
import Watcher from '../observer/watcher'
import { mergeOptions } from '../util/options'
import { isEmpty, looseEqual } from '../util/util'
import initState from './initState'
import { callHook } from './lifecycle'
import initEvent from './initEvent'
let id = 0
@event
export default class DD {
id: number
active: boolean
$options?: any
$parent: any
$root: any
$children?: Array
_watchers?: Array
[key: string]: any
static cid: number
static options: any
static use: any
static extend: any
static mixin: any
constructor(options: any) {
this.id = id++
this._init(options)
this.active = true
}
_init(options: any) {
let dd: DD = this
dd.$children = []
dd._watchers = []
// 合并 构造函数的配置项 和 输入的配置项
var sub: any = dd.constructor
dd.$options = mergeOptions(sub.options, options)
let parent = dd.$options.parent
if (parent) {
parent.$children.push(dd)
dd.$parent = parent
}
// 触发 beforeCreate 事件
callHook(dd, 'beforeCreate')
initState(dd)
// 触发 created 事件
callHook(dd, 'created')
initEvent(dd)
}
// 实例更新 props
$updateProps(propsData: any) {
if (isEmpty(propsData)) return
let dd = this
for (let key in dd.$options.props) {
let value = propsData[key]
if (!value) value = dd.$options.props[key].default
if (!looseEqual(dd[key], value)) dd[key] = value
}
}
// 添加子实例
$addChild(Sub: typeof DD, propsData: any = {}) {
const sub = new Sub({
parent: this,
propsData: propsData
})
for (let k in propsData) {
let key = k
if (k.charAt(0) === ':') key = k.substr(1)
// 实例接受哪些数据由实例自身的 props 属性决定
if (!sub.$options.props[key]) continue
if (k.charAt(0) === ':') {
// 对于动态属性需要添加监听,将父实例的变化映射到子实例中
new Watcher(this, propsData[k], (val: any, oldVal: any) => {
sub[key] = val
})
} else {
sub[key] = propsData[k]
}
}
return sub
}
// 暴露创建监听的方法
// 创建一个观察者,观察者会观察在 getter 中对属性的 get 的操作
// 当对应属性发生 set 动作时,会触发 callback
// 新生成的观察者对象会保存在实例的 _watchers 属性下
$watch(getter: string | Function, callback: Function) {
let dd: DD = this
const watcher = new Watcher(dd, getter, callback)
dd._watchers.push(watcher)
return function unwatchFn () {
watcher.teardown()
}
}
// 暴露销毁当前实例的方法
$destroy() {
if (this.active) {
let dd = this
callHook(dd, 'beforeDestroy')
// 移除父子关系
let parent = dd.$parent
parent.$children.splice(parent.$children.indexOf(dd), 1)
dd.$parent = null
// 注销 watch
while (dd._watchers.length) {
dd._watchers.shift().teardown()
}
// 注销 computed
while (dd._computed.length) {
dd._computed.shift().teardown()
}
// 清空事件
dd.$off()
// 清空子实例
while (dd.$children.length !== 0) {
let child = dd.$children.pop()
child.$destroy()
}
callHook(dd, 'destroyed')
this.active = false
}
}
}