2019-09-07 00:58:31 +08:00
|
|
|
import { ComponentInternalInstance, Data } from './component'
|
2019-09-04 11:04:11 +08:00
|
|
|
import { nextTick } from './scheduler'
|
2019-09-04 23:36:27 +08:00
|
|
|
import { instanceWatch } from './apiWatch'
|
2019-10-02 22:37:06 +08:00
|
|
|
import { EMPTY_OBJ, hasOwn, globalsWhitelist } from '@vue/shared'
|
2019-10-02 22:03:43 +08:00
|
|
|
import { ExtracComputedReturns } from './apiOptions'
|
2019-09-06 23:19:22 +08:00
|
|
|
import { UnwrapRef } from '@vue/reactivity'
|
|
|
|
|
|
|
|
// public properties exposed on the proxy, which is used as the render context
|
|
|
|
// in templates (as `this` in the render option)
|
2019-09-07 00:58:31 +08:00
|
|
|
export type ComponentPublicInstance<
|
2019-09-06 23:19:22 +08:00
|
|
|
P = {},
|
|
|
|
B = {},
|
|
|
|
D = {},
|
|
|
|
C = {},
|
|
|
|
M = {},
|
|
|
|
PublicProps = P
|
|
|
|
> = {
|
|
|
|
$data: D
|
|
|
|
$props: PublicProps
|
|
|
|
$attrs: Data
|
|
|
|
$refs: Data
|
|
|
|
$slots: Data
|
2019-09-07 00:58:31 +08:00
|
|
|
$root: ComponentInternalInstance | null
|
|
|
|
$parent: ComponentInternalInstance | null
|
2019-09-06 23:19:22 +08:00
|
|
|
$emit: (event: string, ...args: unknown[]) => void
|
|
|
|
} & P &
|
|
|
|
UnwrapRef<B> &
|
|
|
|
D &
|
|
|
|
ExtracComputedReturns<C> &
|
|
|
|
M
|
2019-05-29 13:43:46 +08:00
|
|
|
|
2019-09-07 00:58:31 +08:00
|
|
|
export const PublicInstanceProxyHandlers = {
|
|
|
|
get(target: ComponentInternalInstance, key: string) {
|
2019-09-06 08:36:35 +08:00
|
|
|
const { renderContext, data, props, propsProxy } = target
|
2019-09-06 08:48:14 +08:00
|
|
|
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
2019-06-19 17:08:42 +08:00
|
|
|
return data[key]
|
2019-09-06 08:48:14 +08:00
|
|
|
} else if (hasOwn(renderContext, key)) {
|
2019-09-06 08:36:35 +08:00
|
|
|
return renderContext[key]
|
2019-09-06 08:48:14 +08:00
|
|
|
} else if (hasOwn(props, key)) {
|
2019-09-04 03:27:59 +08:00
|
|
|
// return the value from propsProxy for ref unwrapping and readonly
|
2019-10-05 22:09:34 +08:00
|
|
|
return propsProxy![key]
|
2019-05-29 13:43:46 +08:00
|
|
|
} else {
|
2019-09-23 04:50:57 +08:00
|
|
|
// TODO simplify this?
|
2019-05-29 13:43:46 +08:00
|
|
|
switch (key) {
|
2019-06-19 17:08:42 +08:00
|
|
|
case '$data':
|
|
|
|
return data
|
2019-05-29 13:43:46 +08:00
|
|
|
case '$props':
|
2019-09-04 03:27:59 +08:00
|
|
|
return propsProxy
|
2019-05-29 13:43:46 +08:00
|
|
|
case '$attrs':
|
|
|
|
return target.attrs
|
|
|
|
case '$slots':
|
|
|
|
return target.slots
|
|
|
|
case '$refs':
|
|
|
|
return target.refs
|
2019-06-03 13:44:45 +08:00
|
|
|
case '$parent':
|
|
|
|
return target.parent
|
|
|
|
case '$root':
|
|
|
|
return target.root
|
2019-06-19 16:43:34 +08:00
|
|
|
case '$emit':
|
|
|
|
return target.emit
|
2019-09-04 11:04:11 +08:00
|
|
|
case '$el':
|
|
|
|
return target.vnode.el
|
|
|
|
case '$options':
|
|
|
|
return target.type
|
2019-05-29 13:43:46 +08:00
|
|
|
default:
|
2019-09-04 11:04:11 +08:00
|
|
|
// methods are only exposed when options are supported
|
|
|
|
if (__FEATURE_OPTIONS__) {
|
|
|
|
switch (key) {
|
|
|
|
case '$forceUpdate':
|
|
|
|
return target.update
|
|
|
|
case '$nextTick':
|
|
|
|
return nextTick
|
|
|
|
case '$watch':
|
2019-09-04 23:36:27 +08:00
|
|
|
return instanceWatch.bind(target)
|
2019-09-04 11:04:11 +08:00
|
|
|
}
|
|
|
|
}
|
2019-08-21 21:50:20 +08:00
|
|
|
return target.user[key]
|
2019-05-29 13:43:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2019-10-02 22:37:06 +08:00
|
|
|
// this trap is only called in browser-compiled render functions that use
|
|
|
|
// `with (this) {}`
|
|
|
|
has(_: any, key: string): boolean {
|
|
|
|
return key[0] !== '_' && !globalsWhitelist.has(key)
|
2019-09-20 12:12:37 +08:00
|
|
|
},
|
2019-09-07 00:58:31 +08:00
|
|
|
set(target: ComponentInternalInstance, key: string, value: any): boolean {
|
2019-09-06 08:36:35 +08:00
|
|
|
const { data, renderContext } = target
|
2019-09-06 08:48:14 +08:00
|
|
|
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
|
2019-06-19 17:08:42 +08:00
|
|
|
data[key] = value
|
2019-09-06 08:48:14 +08:00
|
|
|
} else if (hasOwn(renderContext, key)) {
|
2019-09-06 08:36:35 +08:00
|
|
|
renderContext[key] = value
|
2019-08-21 21:50:20 +08:00
|
|
|
} else if (key[0] === '$' && key.slice(1) in target) {
|
|
|
|
// TODO warn attempt of mutating public property
|
|
|
|
return false
|
|
|
|
} else if (key in target.props) {
|
|
|
|
// TODO warn attempt of mutating prop
|
|
|
|
return false
|
2019-05-29 13:43:46 +08:00
|
|
|
} else {
|
2019-08-21 21:50:20 +08:00
|
|
|
target.user[key] = value
|
2019-05-29 13:43:46 +08:00
|
|
|
}
|
2019-09-06 08:36:35 +08:00
|
|
|
return true
|
2019-05-29 13:43:46 +08:00
|
|
|
}
|
|
|
|
}
|