vue3-core/packages/runtime-core/src/componentProxy.ts

103 lines
3.1 KiB
TypeScript
Raw Normal View History

2018-10-09 23:37:24 +08:00
import { ComponentInstance } from './component'
2018-10-18 00:20:54 +08:00
import { isFunction, isReservedKey } from '@vue/shared'
2018-10-29 07:15:18 +08:00
import { warn } from './warning'
import { isRendering } from './componentUtils'
import { isObservable } from '@vue/observer'
import { reservedMethods } from '@vue/runtime-dom'
2018-09-19 23:35:38 +08:00
const bindCache = new WeakMap()
function getBoundMethod(fn: Function, target: any, receiver: any): Function {
let boundMethodsForTarget = bindCache.get(target)
if (boundMethodsForTarget === void 0) {
bindCache.set(target, (boundMethodsForTarget = new Map()))
}
let boundFn = boundMethodsForTarget.get(fn)
if (boundFn === void 0) {
boundMethodsForTarget.set(fn, (boundFn = fn.bind(receiver)))
}
return boundFn
}
const renderProxyHandlers = {
2018-10-09 23:37:24 +08:00
get(target: ComponentInstance<any, any>, key: string, receiver: any) {
2018-10-29 07:15:18 +08:00
let i: any
2018-09-19 23:35:38 +08:00
if (key === '_self') {
return target
2018-10-29 07:15:18 +08:00
} else if ((i = target._rawData) !== null && i.hasOwnProperty(key)) {
2018-09-19 23:35:38 +08:00
// data
2018-10-29 07:15:18 +08:00
// make sure to return from $data to register dependency
2018-09-19 23:35:38 +08:00
return target.$data[key]
2018-10-29 07:15:18 +08:00
} else if ((i = target.$options.props) != null && i.hasOwnProperty(key)) {
2018-09-19 23:35:38 +08:00
// props are only proxied if declared
return target.$props[key]
} else if (
2018-10-29 07:15:18 +08:00
(i = target._computedGetters) !== null &&
i.hasOwnProperty(key)
2018-09-19 23:35:38 +08:00
) {
// computed
2018-10-29 07:15:18 +08:00
return i[key]()
} else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
// hooks injections
return i[key]
2018-10-18 00:20:54 +08:00
} else if (key[0] !== '_') {
if (
__DEV__ &&
isRendering &&
!(key in target) &&
!(key in reservedMethods)
) {
2018-10-29 07:15:18 +08:00
warn(
`property "${key}" was accessed during render but does not exist ` +
`on instance.`
2018-10-29 07:15:18 +08:00
)
2018-09-19 23:35:38 +08:00
}
const value = Reflect.get(target, key, receiver)
2018-10-18 05:35:03 +08:00
if (key !== 'constructor' && isFunction(value)) {
2018-09-19 23:35:38 +08:00
// auto bind
return getBoundMethod(value, target, receiver)
} else {
return value
}
}
},
set(
2018-10-09 23:37:24 +08:00
target: ComponentInstance<any, any>,
2018-09-19 23:35:38 +08:00
key: string,
value: any,
receiver: any
): boolean {
2018-10-29 07:15:18 +08:00
let i: any
2018-09-19 23:35:38 +08:00
if (__DEV__) {
2018-10-28 10:10:25 +08:00
if (isReservedKey(key) && key in target) {
2018-10-29 07:15:18 +08:00
warn(`failed setting property "${key}": reserved fields are immutable.`)
2018-09-19 23:35:38 +08:00
return false
}
2018-10-29 07:15:18 +08:00
if ((i = target.$options.props) != null && i.hasOwnProperty(key)) {
warn(`failed setting property "${key}": props are immutable.`)
2018-09-19 23:35:38 +08:00
return false
}
}
2018-10-29 07:15:18 +08:00
if ((i = target._rawData) !== null && i.hasOwnProperty(key)) {
2018-09-19 23:35:38 +08:00
target.$data[key] = value
return true
} else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
if (__DEV__ && !isObservable(i)) {
warn(
`attempting to mutate a property returned from hooks(), but the ` +
`value is not observable.`
)
}
// this enables returning observable objects from hooks()
i[key] = value
return true
2018-09-19 23:35:38 +08:00
} else {
return Reflect.set(target, key, value, receiver)
}
}
}
2018-10-09 23:37:24 +08:00
export function createRenderProxy(instance: any): ComponentInstance {
return new Proxy(instance, renderProxyHandlers) as ComponentInstance
2018-09-19 23:35:38 +08:00
}