init.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* @flow */
  2. import config from '../config'
  3. import { perf } from '../util/perf'
  4. import { initProxy } from './proxy'
  5. import { initState } from './state'
  6. import { initRender } from './render'
  7. import { initEvents } from './events'
  8. import { initInjections } from './inject'
  9. import { initLifecycle, callHook } from './lifecycle'
  10. import { extend, mergeOptions, formatComponentName } from '../util/index'
  11. let uid = 0
  12. export function initMixin (Vue: Class<Component>) {
  13. Vue.prototype._init = function (options?: Object) {
  14. /* istanbul ignore if */
  15. if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
  16. perf.mark('init')
  17. }
  18. const vm: Component = this
  19. // a uid
  20. vm._uid = uid++
  21. // a flag to avoid this being observed
  22. vm._isVue = true
  23. // merge options
  24. if (options && options._isComponent) {
  25. // optimize internal component instantiation
  26. // since dynamic options merging is pretty slow, and none of the
  27. // internal component options needs special treatment.
  28. initInternalComponent(vm, options)
  29. } else {
  30. vm.$options = mergeOptions(
  31. resolveConstructorOptions(vm.constructor),
  32. options || {},
  33. vm
  34. )
  35. }
  36. /* istanbul ignore else */
  37. if (process.env.NODE_ENV !== 'production') {
  38. initProxy(vm)
  39. } else {
  40. vm._renderProxy = vm
  41. }
  42. // expose real self
  43. vm._self = vm
  44. initLifecycle(vm)
  45. initEvents(vm)
  46. initRender(vm)
  47. callHook(vm, 'beforeCreate')
  48. initState(vm)
  49. initInjections(vm)
  50. callHook(vm, 'created')
  51. /* istanbul ignore if */
  52. if (process.env.NODE_ENV !== 'production' && config.performance && perf) {
  53. vm._name = formatComponentName(vm, false)
  54. perf.mark('init end')
  55. perf.measure(`${vm._name} init`, 'init', 'init end')
  56. }
  57. if (vm.$options.el) {
  58. vm.$mount(vm.$options.el)
  59. }
  60. }
  61. }
  62. function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  63. const opts = vm.$options = Object.create(vm.constructor.options)
  64. // doing this because it's faster than dynamic enumeration.
  65. opts.parent = options.parent
  66. opts.propsData = options.propsData
  67. opts._parentVnode = options._parentVnode
  68. opts._parentListeners = options._parentListeners
  69. opts._renderChildren = options._renderChildren
  70. opts._componentTag = options._componentTag
  71. opts._parentElm = options._parentElm
  72. opts._refElm = options._refElm
  73. if (options.render) {
  74. opts.render = options.render
  75. opts.staticRenderFns = options.staticRenderFns
  76. }
  77. }
  78. export function resolveConstructorOptions (Ctor: Class<Component>) {
  79. let options = Ctor.options
  80. if (Ctor.super) {
  81. const superOptions = resolveConstructorOptions(Ctor.super)
  82. const cachedSuperOptions = Ctor.superOptions
  83. if (superOptions !== cachedSuperOptions) {
  84. // super option changed,
  85. // need to resolve new options.
  86. Ctor.superOptions = superOptions
  87. // check if there are any late-modified/attached options (#4976)
  88. const modifiedOptions = resolveModifiedOptions(Ctor)
  89. // update base extend options
  90. if (modifiedOptions) {
  91. extend(Ctor.extendOptions, modifiedOptions)
  92. }
  93. options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
  94. if (options.name) {
  95. options.components[options.name] = Ctor
  96. }
  97. }
  98. }
  99. return options
  100. }
  101. function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
  102. let modified
  103. const latest = Ctor.options
  104. const sealed = Ctor.sealedOptions
  105. for (const key in latest) {
  106. if (latest[key] !== sealed[key]) {
  107. if (!modified) modified = {}
  108. modified[key] = dedupe(latest[key], sealed[key])
  109. }
  110. }
  111. return modified
  112. }
  113. function dedupe (latest, sealed) {
  114. // compare latest and sealed to ensure lifecycle hooks won't be duplicated
  115. // between merges
  116. if (Array.isArray(latest)) {
  117. const res = []
  118. sealed = Array.isArray(sealed) ? sealed : [sealed]
  119. for (let i = 0; i < latest.length; i++) {
  120. if (sealed.indexOf(latest[i]) < 0) {
  121. res.push(latest[i])
  122. }
  123. }
  124. return res
  125. } else {
  126. return latest
  127. }
  128. }