override.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { getWatcher, getDep } from './util'
  2. export default function (Vue) {
  3. const version = Number(Vue.version.split('.')[0])
  4. if (version >= 2) {
  5. const usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1
  6. Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit })
  7. } else {
  8. // override init and inject vuex init procedure
  9. // for 1.x backwards compatibility.
  10. const _init = Vue.prototype._init
  11. Vue.prototype._init = function (options = {}) {
  12. options.init = options.init
  13. ? [vuexInit].concat(options.init)
  14. : vuexInit
  15. _init.call(this, options)
  16. }
  17. }
  18. /**
  19. * Vuex init hook, injected into each instances init hooks list.
  20. */
  21. function vuexInit () {
  22. const options = this.$options
  23. const { store, vuex } = options
  24. // store injection
  25. if (store) {
  26. this.$store = store
  27. } else if (options.parent && options.parent.$store) {
  28. this.$store = options.parent.$store
  29. }
  30. // vuex option handling
  31. if (vuex) {
  32. if (!this.$store) {
  33. console.warn(
  34. '[vuex] store not injected. make sure to ' +
  35. 'provide the store option in your root component.'
  36. )
  37. }
  38. const { state, actions } = vuex
  39. let { getters } = vuex
  40. // handle deprecated state option
  41. if (state && !getters) {
  42. console.warn(
  43. '[vuex] vuex.state option will been deprecated in 1.0. ' +
  44. 'Use vuex.getters instead.'
  45. )
  46. getters = state
  47. }
  48. // getters
  49. if (getters) {
  50. options.computed = options.computed || {}
  51. for (const key in getters) {
  52. defineVuexGetter(this, key, getters[key])
  53. }
  54. }
  55. // actions
  56. if (actions) {
  57. options.methods = options.methods || {}
  58. for (const key in actions) {
  59. options.methods[key] = makeBoundAction(this.$store, actions[key], key)
  60. }
  61. }
  62. }
  63. }
  64. /**
  65. * Setter for all getter properties.
  66. */
  67. function setter () {
  68. throw new Error('vuex getter properties are read-only.')
  69. }
  70. /**
  71. * Define a Vuex getter on an instance.
  72. *
  73. * @param {Vue} vm
  74. * @param {String} key
  75. * @param {Function} getter
  76. */
  77. function defineVuexGetter (vm, key, getter) {
  78. if (typeof getter !== 'function') {
  79. console.warn(`[vuex] Getter bound to key 'vuex.getters.${key}' is not a function.`)
  80. } else {
  81. Object.defineProperty(vm, key, {
  82. enumerable: true,
  83. configurable: true,
  84. get: makeComputedGetter(vm.$store, getter),
  85. set: setter
  86. })
  87. }
  88. }
  89. /**
  90. * Make a computed getter, using the same caching mechanism of computed
  91. * properties. In addition, it is cached on the raw getter function using
  92. * the store's unique cache id. This makes the same getter shared
  93. * across all components use the same underlying watcher, and makes
  94. * the getter evaluated only once during every flush.
  95. *
  96. * @param {Store} store
  97. * @param {Function} getter
  98. */
  99. function makeComputedGetter (store, getter) {
  100. const id = store._getterCacheId
  101. // cached
  102. if (getter[id]) {
  103. return getter[id]
  104. }
  105. const vm = store._vm
  106. const Watcher = getWatcher(vm)
  107. const Dep = getDep(vm)
  108. const watcher = new Watcher(
  109. vm,
  110. vm => getter(vm.state),
  111. null,
  112. { lazy: true }
  113. )
  114. const computedGetter = () => {
  115. if (watcher.dirty) {
  116. watcher.evaluate()
  117. }
  118. if (Dep.target) {
  119. watcher.depend()
  120. }
  121. return watcher.value
  122. }
  123. getter[id] = computedGetter
  124. return computedGetter
  125. }
  126. /**
  127. * Make a bound-to-store version of a raw action function.
  128. *
  129. * @param {Store} store
  130. * @param {Function} action
  131. * @param {String} key
  132. */
  133. function makeBoundAction (store, action, key) {
  134. if (typeof action !== 'function') {
  135. console.warn(`[vuex] Action bound to key 'vuex.actions.${key}' is not a function.`)
  136. }
  137. return function vuexBoundAction (...args) {
  138. return action.call(this, store, ...args)
  139. }
  140. }
  141. // option merging
  142. const merge = Vue.config.optionMergeStrategies.computed
  143. Vue.config.optionMergeStrategies.vuex = (toVal, fromVal) => {
  144. if (!toVal) return fromVal
  145. if (!fromVal) return toVal
  146. return {
  147. getters: merge(toVal.getters, fromVal.getters),
  148. state: merge(toVal.state, fromVal.state),
  149. actions: merge(toVal.actions, fromVal.actions)
  150. }
  151. }
  152. }