2
0

componentProxy.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { ComponentInstance } from './component'
  2. import { isFunction, isReservedKey } from '@vue/shared'
  3. import { warn } from './warning'
  4. import { isRendering } from './componentRenderUtils'
  5. import { isObservable } from '@vue/observer'
  6. import { reservedMethods } from './componentOptions'
  7. const bindCache = new WeakMap()
  8. function getBoundMethod(fn: Function, target: any, receiver: any): Function {
  9. let boundMethodsForTarget = bindCache.get(target)
  10. if (boundMethodsForTarget === void 0) {
  11. bindCache.set(target, (boundMethodsForTarget = new Map()))
  12. }
  13. let boundFn = boundMethodsForTarget.get(fn)
  14. if (boundFn === void 0) {
  15. boundMethodsForTarget.set(fn, (boundFn = fn.bind(receiver)))
  16. }
  17. return boundFn
  18. }
  19. const renderProxyHandlers = {
  20. get(target: ComponentInstance<any, any>, key: string, receiver: any) {
  21. let i: any
  22. if (key === '_self') {
  23. return target
  24. } else if ((i = target._rawData) !== null && i.hasOwnProperty(key)) {
  25. // data
  26. // make sure to return from $data to register dependency
  27. return target.$data[key]
  28. } else if ((i = target.$options.props) != null && i.hasOwnProperty(key)) {
  29. // props are only proxied if declared
  30. return target.$props[key]
  31. } else if (
  32. (i = target._computedGetters) !== null &&
  33. i.hasOwnProperty(key)
  34. ) {
  35. // computed
  36. return i[key]()
  37. } else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
  38. // hooks injections
  39. return i[key]
  40. } else if (key[0] !== '_') {
  41. if (
  42. __DEV__ &&
  43. isRendering &&
  44. !(key in target) &&
  45. !(key in reservedMethods)
  46. ) {
  47. warn(
  48. `property "${key}" was accessed during render but does not exist ` +
  49. `on instance.`
  50. )
  51. }
  52. const value = Reflect.get(target, key, receiver)
  53. if (key !== 'constructor' && isFunction(value)) {
  54. // auto bind
  55. return getBoundMethod(value, target, receiver)
  56. } else {
  57. return value
  58. }
  59. }
  60. },
  61. set(
  62. target: ComponentInstance<any, any>,
  63. key: string,
  64. value: any,
  65. receiver: any
  66. ): boolean {
  67. let i: any
  68. if (__DEV__) {
  69. if (isReservedKey(key) && key in target) {
  70. warn(`failed setting property "${key}": reserved fields are immutable.`)
  71. return false
  72. }
  73. if ((i = target.$options.props) != null && i.hasOwnProperty(key)) {
  74. warn(`failed setting property "${key}": props are immutable.`)
  75. return false
  76. }
  77. }
  78. if ((i = target._rawData) !== null && i.hasOwnProperty(key)) {
  79. target.$data[key] = value
  80. return true
  81. } else if ((i = target._hookProps) !== null && i.hasOwnProperty(key)) {
  82. if (__DEV__ && !isObservable(i)) {
  83. warn(
  84. `attempting to mutate a property returned from hooks(), but the ` +
  85. `value is not observable.`
  86. )
  87. }
  88. // this enables returning observable objects from hooks()
  89. i[key] = value
  90. return true
  91. } else {
  92. return Reflect.set(target, key, value, receiver)
  93. }
  94. }
  95. }
  96. export function createRenderProxy(instance: any): ComponentInstance {
  97. return new Proxy(instance, renderProxyHandlers) as ComponentInstance
  98. }