vuex.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /**
  2. * vuex v2.0.0-rc.5
  3. * (c) 2016 Evan You
  4. * @license MIT
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global.Vuex = factory());
  10. }(this, function () { 'use strict';
  11. var devtoolHook =
  12. typeof window !== 'undefined' &&
  13. window.__VUE_DEVTOOLS_GLOBAL_HOOK__
  14. function devtoolPlugin (store) {
  15. if (!devtoolHook) return
  16. store._devtoolHook = devtoolHook
  17. devtoolHook.emit('vuex:init', store)
  18. devtoolHook.on('vuex:travel-to-state', function (targetState) {
  19. store.replaceState(targetState)
  20. })
  21. store.subscribe(function (mutation, state) {
  22. devtoolHook.emit('vuex:mutation', mutation, state)
  23. })
  24. }
  25. function applyMixin (Vue) {
  26. var version = Number(Vue.version.split('.')[0])
  27. if (version >= 2) {
  28. var usesInit = Vue.config._lifecycleHooks.indexOf('init') > -1
  29. Vue.mixin(usesInit ? { init: vuexInit } : { beforeCreate: vuexInit })
  30. } else {
  31. // override init and inject vuex init procedure
  32. // for 1.x backwards compatibility.
  33. var _init = Vue.prototype._init
  34. Vue.prototype._init = function (options) {
  35. if ( options === void 0 ) options = {};
  36. options.init = options.init
  37. ? [vuexInit].concat(options.init)
  38. : vuexInit
  39. _init.call(this, options)
  40. }
  41. }
  42. /**
  43. * Vuex init hook, injected into each instances init hooks list.
  44. */
  45. function vuexInit () {
  46. var options = this.$options
  47. // store injection
  48. if (options.store) {
  49. this.$store = options.store
  50. } else if (options.parent && options.parent.$store) {
  51. this.$store = options.parent.$store
  52. }
  53. }
  54. }
  55. function mapState (states) {
  56. var res = {}
  57. normalizeMap(states).forEach(function (ref) {
  58. var key = ref.key;
  59. var val = ref.val;
  60. res[key] = function mappedState () {
  61. return typeof val === 'function'
  62. ? val.call(this, this.$store.state, this.$store.getters)
  63. : this.$store.state[val]
  64. }
  65. })
  66. return res
  67. }
  68. function mapMutations (mutations) {
  69. var res = {}
  70. normalizeMap(mutations).forEach(function (ref) {
  71. var key = ref.key;
  72. var val = ref.val;
  73. res[key] = function mappedMutation () {
  74. var args = [], len = arguments.length;
  75. while ( len-- ) args[ len ] = arguments[ len ];
  76. return this.$store.commit.apply(this.$store, [val].concat(args))
  77. }
  78. })
  79. return res
  80. }
  81. function mapGetters (getters) {
  82. var res = {}
  83. normalizeMap(getters).forEach(function (ref) {
  84. var key = ref.key;
  85. var val = ref.val;
  86. res[key] = function mappedGetter () {
  87. if (!(val in this.$store.getters)) {
  88. console.error(("[vuex] unknown getter: " + val))
  89. }
  90. return this.$store.getters[val]
  91. }
  92. })
  93. return res
  94. }
  95. function mapActions (actions) {
  96. var res = {}
  97. normalizeMap(actions).forEach(function (ref) {
  98. var key = ref.key;
  99. var val = ref.val;
  100. res[key] = function mappedAction () {
  101. var args = [], len = arguments.length;
  102. while ( len-- ) args[ len ] = arguments[ len ];
  103. return this.$store.dispatch.apply(this.$store, [val].concat(args))
  104. }
  105. })
  106. return res
  107. }
  108. function normalizeMap (map) {
  109. return Array.isArray(map)
  110. ? map.map(function (key) { return ({ key: key, val: key }); })
  111. : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
  112. }
  113. var Vue // bind on install
  114. var Store = function Store (options) {
  115. var this$1 = this;
  116. if ( options === void 0 ) options = {};
  117. assert(Vue, "must call Vue.use(Vuex) before creating a store instance.")
  118. assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser.")
  119. var state = options.state; if ( state === void 0 ) state = {};
  120. var plugins = options.plugins; if ( plugins === void 0 ) plugins = [];
  121. var strict = options.strict; if ( strict === void 0 ) strict = false;
  122. // store internal state
  123. this._options = options
  124. this._committing = false
  125. this._actions = Object.create(null)
  126. this._mutations = Object.create(null)
  127. this._wrappedGetters = Object.create(null)
  128. this._runtimeModules = Object.create(null)
  129. this._subscribers = []
  130. this._watcherVM = new Vue()
  131. // bind commit and dispatch to self
  132. var store = this
  133. var ref = this;
  134. var dispatch = ref.dispatch;
  135. var commit = ref.commit;
  136. this.dispatch = function boundDispatch (type, payload) {
  137. return dispatch.call(store, type, payload)
  138. }
  139. this.commit = function boundCommit (type, payload, options) {
  140. return commit.call(store, type, payload, options)
  141. }
  142. // strict mode
  143. this.strict = strict
  144. // init root module.
  145. // this also recursively registers all sub-modules
  146. // and collects all module getters inside this._wrappedGetters
  147. installModule(this, state, [], options)
  148. // initialize the store vm, which is responsible for the reactivity
  149. // (also registers _wrappedGetters as computed properties)
  150. resetStoreVM(this, state)
  151. // apply plugins
  152. plugins.concat(devtoolPlugin).forEach(function (plugin) { return plugin(this$1); })
  153. };
  154. var prototypeAccessors = { state: {} };
  155. prototypeAccessors.state.get = function () {
  156. return this._vm.state
  157. };
  158. prototypeAccessors.state.set = function (v) {
  159. assert(false, "Use store.replaceState() to explicit replace store state.")
  160. };
  161. Store.prototype.commit = function commit (type, payload, options) {
  162. var this$1 = this;
  163. // check object-style commit
  164. var mutation
  165. if (isObject(type) && type.type) {
  166. options = payload
  167. payload = mutation = type
  168. type = type.type
  169. } else {
  170. mutation = { type: type, payload: payload }
  171. }
  172. var entry = this._mutations[type]
  173. if (!entry) {
  174. console.error(("[vuex] unknown mutation type: " + type))
  175. return
  176. }
  177. this._withCommit(function () {
  178. entry.forEach(function commitIterator (handler) {
  179. handler(payload)
  180. })
  181. })
  182. if (!options || !options.silent) {
  183. this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); })
  184. }
  185. };
  186. Store.prototype.dispatch = function dispatch (type, payload) {
  187. var entry = this._actions[type]
  188. if (!entry) {
  189. console.error(("[vuex] unknown action type: " + type))
  190. return
  191. }
  192. return entry.length > 1
  193. ? Promise.all(entry.map(function (handler) { return handler(payload); }))
  194. : entry[0](payload)
  195. };
  196. Store.prototype.subscribe = function subscribe (fn) {
  197. var subs = this._subscribers
  198. if (subs.indexOf(fn) < 0) {
  199. subs.push(fn)
  200. }
  201. return function () {
  202. var i = subs.indexOf(fn)
  203. if (i > -1) {
  204. subs.splice(i, 1)
  205. }
  206. }
  207. };
  208. Store.prototype.watch = function watch (getter, cb, options) {
  209. var this$1 = this;
  210. assert(typeof getter === 'function', "store.watch only accepts a function.")
  211. return this._watcherVM.$watch(function () { return getter(this$1.state); }, cb, options)
  212. };
  213. Store.prototype.replaceState = function replaceState (state) {
  214. var this$1 = this;
  215. this._withCommit(function () {
  216. this$1._vm.state = state
  217. })
  218. };
  219. Store.prototype.registerModule = function registerModule (path, module) {
  220. if (typeof path === 'string') path = [path]
  221. assert(Array.isArray(path), "module path must be a string or an Array.")
  222. this._runtimeModules[path.join('.')] = module
  223. installModule(this, this.state, path, module)
  224. // reset store to update getters...
  225. resetStoreVM(this, this.state)
  226. };
  227. Store.prototype.unregisterModule = function unregisterModule (path) {
  228. var this$1 = this;
  229. if (typeof path === 'string') path = [path]
  230. assert(Array.isArray(path), "module path must be a string or an Array.")
  231. delete this._runtimeModules[path.join('.')]
  232. this._withCommit(function () {
  233. var parentState = getNestedState(this$1.state, path.slice(0, -1))
  234. Vue.delete(parentState, path[path.length - 1])
  235. })
  236. resetStore(this)
  237. };
  238. Store.prototype.hotUpdate = function hotUpdate (newOptions) {
  239. var options = this._options
  240. if (newOptions.actions) {
  241. options.actions = newOptions.actions
  242. }
  243. if (newOptions.mutations) {
  244. options.mutations = newOptions.mutations
  245. }
  246. if (newOptions.getters) {
  247. options.getters = newOptions.getters
  248. }
  249. if (newOptions.modules) {
  250. for (var key in newOptions.modules) {
  251. options.modules[key] = newOptions.modules[key]
  252. }
  253. }
  254. resetStore(this)
  255. };
  256. Store.prototype._withCommit = function _withCommit (fn) {
  257. var committing = this._committing
  258. this._committing = true
  259. fn()
  260. this._committing = committing
  261. };
  262. Object.defineProperties( Store.prototype, prototypeAccessors );
  263. function assert (condition, msg) {
  264. if (!condition) throw new Error(("[vuex] " + msg))
  265. }
  266. function resetStore (store) {
  267. store._actions = Object.create(null)
  268. store._mutations = Object.create(null)
  269. store._wrappedGetters = Object.create(null)
  270. var state = store.state
  271. // init root module
  272. installModule(store, state, [], store._options, true)
  273. // init all runtime modules
  274. Object.keys(store._runtimeModules).forEach(function (key) {
  275. installModule(store, state, key.split('.'), store._runtimeModules[key], true)
  276. })
  277. // reset vm
  278. resetStoreVM(store, state)
  279. }
  280. function resetStoreVM (store, state) {
  281. var oldVm = store._vm
  282. // bind store public getters
  283. store.getters = {}
  284. var wrappedGetters = store._wrappedGetters
  285. var computed = {}
  286. Object.keys(wrappedGetters).forEach(function (key) {
  287. var fn = wrappedGetters[key]
  288. // use computed to leverage its lazy-caching mechanism
  289. computed[key] = function () { return fn(store); }
  290. Object.defineProperty(store.getters, key, {
  291. get: function () { return store._vm[key]; }
  292. })
  293. })
  294. // use a Vue instance to store the state tree
  295. // suppress warnings just in case the user has added
  296. // some funky global mixins
  297. var silent = Vue.config.silent
  298. Vue.config.silent = true
  299. store._vm = new Vue({
  300. data: { state: state },
  301. computed: computed
  302. })
  303. Vue.config.silent = silent
  304. // enable strict mode for new vm
  305. if (store.strict) {
  306. enableStrictMode(store)
  307. }
  308. if (oldVm) {
  309. // dispatch changes in all subscribed watchers
  310. // to force getter re-evaluation.
  311. store._withCommit(function () {
  312. oldVm.state = null
  313. })
  314. Vue.nextTick(function () { return oldVm.$destroy(); })
  315. }
  316. }
  317. function installModule (store, rootState, path, module, hot) {
  318. var isRoot = !path.length
  319. var state = module.state;
  320. var actions = module.actions;
  321. var mutations = module.mutations;
  322. var getters = module.getters;
  323. var modules = module.modules;
  324. // set state
  325. if (!isRoot && !hot) {
  326. var parentState = getNestedState(rootState, path.slice(0, -1))
  327. var moduleName = path[path.length - 1]
  328. store._withCommit(function () {
  329. Vue.set(parentState, moduleName, state || {})
  330. })
  331. }
  332. if (mutations) {
  333. Object.keys(mutations).forEach(function (key) {
  334. registerMutation(store, key, mutations[key], path)
  335. })
  336. }
  337. if (actions) {
  338. Object.keys(actions).forEach(function (key) {
  339. registerAction(store, key, actions[key], path)
  340. })
  341. }
  342. if (getters) {
  343. wrapGetters(store, getters, path)
  344. }
  345. if (modules) {
  346. Object.keys(modules).forEach(function (key) {
  347. installModule(store, rootState, path.concat(key), modules[key], hot)
  348. })
  349. }
  350. }
  351. function registerMutation (store, type, handler, path) {
  352. if ( path === void 0 ) path = [];
  353. var entry = store._mutations[type] || (store._mutations[type] = [])
  354. entry.push(function wrappedMutationHandler (payload) {
  355. handler(getNestedState(store.state, path), payload)
  356. })
  357. }
  358. function registerAction (store, type, handler, path) {
  359. if ( path === void 0 ) path = [];
  360. var entry = store._actions[type] || (store._actions[type] = [])
  361. var dispatch = store.dispatch;
  362. var commit = store.commit;
  363. entry.push(function wrappedActionHandler (payload, cb) {
  364. var res = handler({
  365. dispatch: dispatch,
  366. commit: commit,
  367. getters: store.getters,
  368. state: getNestedState(store.state, path),
  369. rootState: store.state
  370. }, payload, cb)
  371. if (!isPromise(res)) {
  372. res = Promise.resolve(res)
  373. }
  374. if (store._devtoolHook) {
  375. return res.catch(function (err) {
  376. store._devtoolHook.emit('vuex:error', err)
  377. throw err
  378. })
  379. } else {
  380. return res
  381. }
  382. })
  383. }
  384. function wrapGetters (store, moduleGetters, modulePath) {
  385. Object.keys(moduleGetters).forEach(function (getterKey) {
  386. var rawGetter = moduleGetters[getterKey]
  387. if (store._wrappedGetters[getterKey]) {
  388. console.error(("[vuex] duplicate getter key: " + getterKey))
  389. return
  390. }
  391. store._wrappedGetters[getterKey] = function wrappedGetter (store) {
  392. return rawGetter(
  393. getNestedState(store.state, modulePath), // local state
  394. store.getters, // getters
  395. store.state // root state
  396. )
  397. }
  398. })
  399. }
  400. function enableStrictMode (store) {
  401. store._vm.$watch('state', function () {
  402. assert(store._committing, "Do not mutate vuex store state outside mutation handlers.")
  403. }, { deep: true, sync: true })
  404. }
  405. function isObject (obj) {
  406. return obj !== null && typeof obj === 'object'
  407. }
  408. function isPromise (val) {
  409. return val && typeof val.then === 'function'
  410. }
  411. function getNestedState (state, path) {
  412. return path.length
  413. ? path.reduce(function (state, key) { return state[key]; }, state)
  414. : state
  415. }
  416. function install (_Vue) {
  417. if (Vue) {
  418. console.error(
  419. '[vuex] already installed. Vue.use(Vuex) should be called only once.'
  420. )
  421. return
  422. }
  423. Vue = _Vue
  424. applyMixin(Vue)
  425. }
  426. // auto install in dist mode
  427. if (typeof window !== 'undefined' && window.Vue) {
  428. install(window.Vue)
  429. }
  430. var index = {
  431. Store: Store,
  432. install: install,
  433. mapState: mapState,
  434. mapMutations: mapMutations,
  435. mapGetters: mapGetters,
  436. mapActions: mapActions
  437. }
  438. return index;
  439. }));