/
instance.ts
147 lines (138 loc) · 3.98 KB
/
instance.ts
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { ComponentInstance } from '../component'
import vmStateManager from './vmStateManager'
import { setCurrentInstance, getCurrentVue2Instance } from '../runtimeContext'
import { Ref, isRef, isReactive } from '../apis'
import { hasOwn, proxy, warn } from './utils'
import { createSlotProxy, resolveSlots } from './helper'
export function asVmProperty(
vm: ComponentInstance,
propName: string,
propValue: Ref<unknown>
) {
const props = vm.$options.props
if (!(propName in vm) && !(props && hasOwn(props, propName))) {
if (isRef(propValue)) {
proxy(vm, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})
} else {
Object.defineProperty(vm, propName, {
enumerable: true,
configurable: true,
get: () => {
if (isReactive(propValue)) {
;(propValue as any).__ob__.dep.depend()
}
return propValue
},
set: (val) => {
propValue = val
},
})
}
if (__DEV__) {
// expose binding to Vue Devtool as a data property
// delay this until state has been resolved to prevent repeated works
vm.$nextTick(() => {
if (Object.keys(vm._data).indexOf(propName) !== -1) {
return
}
if (isRef(propValue)) {
proxy(vm._data, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})
} else {
proxy(vm._data, propName, {
get: () => propValue,
set: (val: any) => {
propValue = val
},
})
}
})
}
} else if (__DEV__) {
if (props && hasOwn(props, propName)) {
warn(
`The setup binding property "${propName}" is already declared as a prop.`,
vm
)
} else {
warn(`The setup binding property "${propName}" is already declared.`, vm)
}
}
}
export function updateTemplateRef(vm: ComponentInstance) {
const rawBindings = vmStateManager.get(vm, 'rawBindings') || {}
if (!rawBindings || !Object.keys(rawBindings).length) return
const refs = vm.$refs
const oldRefKeys = vmStateManager.get(vm, 'refs') || []
for (let index = 0; index < oldRefKeys.length; index++) {
const key = oldRefKeys[index]
const setupValue = rawBindings[key]
if (!refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = null
}
}
const newKeys = Object.keys(refs)
const validNewKeys = []
for (let index = 0; index < newKeys.length; index++) {
const key = newKeys[index]
const setupValue = rawBindings[key]
if (refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = refs[key]
validNewKeys.push(key)
}
}
vmStateManager.set(vm, 'refs', validNewKeys)
}
export function resolveScopedSlots(
vm: ComponentInstance,
slotsProxy: { [x: string]: Function }
): void {
const parentVNode = (vm.$options as any)._parentVnode
if (!parentVNode) return
const prevSlots = vmStateManager.get(vm, 'slots') || []
const curSlots = resolveSlots(parentVNode.data.scopedSlots, vm.$slots)
// remove staled slots
for (let index = 0; index < prevSlots.length; index++) {
const key = prevSlots[index]
if (!curSlots[key]) {
delete slotsProxy[key]
}
}
// proxy fresh slots
const slotNames = Object.keys(curSlots)
for (let index = 0; index < slotNames.length; index++) {
const key = slotNames[index]
if (!slotsProxy[key]) {
slotsProxy[key] = createSlotProxy(vm, key)
}
}
vmStateManager.set(vm, 'slots', slotNames)
}
export function activateCurrentInstance(
vm: ComponentInstance,
fn: (vm_: ComponentInstance) => any,
onError?: (err: Error) => void
) {
let preVm = getCurrentVue2Instance()
setCurrentInstance(vm)
try {
return fn(vm)
} catch (err) {
if (onError) {
onError(err)
} else {
throw err
}
} finally {
setCurrentInstance(preVm)
}
}