init.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* @flow */
  2. import config from '../config'
  3. import { initProxy } from './proxy'
  4. import { initState } from './state'
  5. import { initRender } from './render'
  6. import { initEvents } from './events'
  7. import { mark, measure } from '../util/perf'
  8. import { initLifecycle, callHook } from './lifecycle'
  9. import { initProvide, initInjections } from './inject'
  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 && mark) {
  16. 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. initInjections(vm) // resolve injections before data/props
  49. initState(vm)
  50. initProvide(vm) // resolve provide after data/props
  51. callHook(vm, 'created')
  52. /* istanbul ignore if */
  53. if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
  54. vm._name = formatComponentName(vm, false)
  55. mark('init end')
  56. measure(`${vm._name} init`, 'init', 'init end')
  57. }
  58. if (vm.$options.el) {
  59. vm.$mount(vm.$options.el)
  60. }
  61. }
  62. }
  63. function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  64. const opts = vm.$options = Object.create(vm.constructor.options)
  65. // doing this because it's faster than dynamic enumeration.
  66. opts.parent = options.parent
  67. opts.propsData = options.propsData
  68. opts._parentVnode = options._parentVnode
  69. opts._parentListeners = options._parentListeners
  70. opts._renderChildren = options._renderChildren
  71. opts._componentTag = options._componentTag
  72. opts._parentElm = options._parentElm
  73. opts._refElm = options._refElm
  74. if (options.render) {
  75. opts.render = options.render
  76. opts.staticRenderFns = options.staticRenderFns
  77. }
  78. }
  79. export function resolveConstructorOptions (Ctor: Class<Component>) {
  80. let options = Ctor.options
  81. if (Ctor.super) {
  82. const superOptions = resolveConstructorOptions(Ctor.super)
  83. const cachedSuperOptions = Ctor.superOptions
  84. if (superOptions !== cachedSuperOptions) {
  85. // super option changed,
  86. // need to resolve new options.
  87. Ctor.superOptions = superOptions
  88. // check if there are any late-modified/attached options (#4976)
  89. const modifiedOptions = resolveModifiedOptions(Ctor)
  90. // update base extend options
  91. if (modifiedOptions) {
  92. extend(Ctor.extendOptions, modifiedOptions)
  93. }
  94. options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
  95. if (options.name) {
  96. options.components[options.name] = Ctor
  97. }
  98. }
  99. }
  100. return options
  101. }
  102. function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
  103. let modified
  104. const latest = Ctor.options
  105. const sealed = Ctor.sealedOptions
  106. for (const key in latest) {
  107. if (latest[key] !== sealed[key]) {
  108. if (!modified) modified = {}
  109. modified[key] = dedupe(latest[key], sealed[key])
  110. }
  111. }
  112. return modified
  113. }
  114. function dedupe (latest, sealed) {
  115. // compare latest and sealed to ensure lifecycle hooks won't be duplicated
  116. // between merges
  117. if (Array.isArray(latest)) {
  118. const res = []
  119. sealed = Array.isArray(sealed) ? sealed : [sealed]
  120. for (let i = 0; i < latest.length; i++) {
  121. if (sealed.indexOf(latest[i]) < 0) {
  122. res.push(latest[i])
  123. }
  124. }
  125. return res
  126. } else {
  127. return latest
  128. }
  129. }