vuex.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /**
  2. * vuex v2.0.0-rc.4
  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._pendingActions = []
  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) {
  140. return commit.call(store, type, payload)
  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) {
  162. var this$1 = this;
  163. // check object-style commit
  164. var mutation
  165. if (isObject(type) && type.type) {
  166. payload = mutation = type
  167. type = type.type
  168. } else {
  169. mutation = { type: type, payload: payload }
  170. }
  171. var entry = this._mutations[type]
  172. if (!entry) {
  173. console.error(("[vuex] unknown mutation type: " + type))
  174. return
  175. }
  176. this._withCommit(function () {
  177. entry.forEach(function commitIterator (handler) {
  178. handler(payload)
  179. })
  180. })
  181. if (!payload || !payload.silent) {
  182. this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); })
  183. }
  184. };
  185. Store.prototype.dispatch = function dispatch (type, payload) {
  186. var entry = this._actions[type]
  187. if (!entry) {
  188. console.error(("[vuex] unknown action type: " + type))
  189. return
  190. }
  191. var res = entry.length > 1
  192. ? Promise.all(entry.map(function (handler) { return handler(payload); }))
  193. : entry[0](payload)
  194. var pending = this._pendingActions
  195. pending.push(res)
  196. return res.then(function (value) {
  197. pending.splice(pending.indexOf(res), 1)
  198. return value
  199. })
  200. };
  201. Store.prototype.subscribe = function subscribe (fn) {
  202. var subs = this._subscribers
  203. if (subs.indexOf(fn) < 0) {
  204. subs.push(fn)
  205. }
  206. return function () {
  207. var i = subs.indexOf(fn)
  208. if (i > -1) {
  209. subs.splice(i, 1)
  210. }
  211. }
  212. };
  213. Store.prototype.watch = function watch (getter, cb, options) {
  214. var this$1 = this;
  215. assert(typeof getter === 'function', "store.watch only accepts a function.")
  216. return this._vm.$watch(function () { return getter(this$1.state); }, cb, options)
  217. };
  218. Store.prototype.replaceState = function replaceState (state) {
  219. var this$1 = this;
  220. this._withCommit(function () {
  221. this$1._vm.state = state
  222. })
  223. };
  224. Store.prototype.registerModule = function registerModule (path, module) {
  225. if (typeof path === 'string') path = [path]
  226. assert(Array.isArray(path), "module path must be a string or an Array.")
  227. this._runtimeModules[path.join('.')] = module
  228. installModule(this, this.state, path, module)
  229. // reset store to update getters...
  230. resetStoreVM(this, this.state)
  231. };
  232. Store.prototype.unregisterModule = function unregisterModule (path) {
  233. var this$1 = this;
  234. if (typeof path === 'string') path = [path]
  235. assert(Array.isArray(path), "module path must be a string or an Array.")
  236. delete this._runtimeModules[path.join('.')]
  237. this._withCommit(function () {
  238. var parentState = getNestedState(this$1.state, path.slice(0, -1))
  239. Vue.delete(parentState, path[path.length - 1])
  240. })
  241. resetStore(this)
  242. };
  243. Store.prototype.hotUpdate = function hotUpdate (newOptions) {
  244. var options = this._options
  245. if (newOptions.actions) {
  246. options.actions = newOptions.actions
  247. }
  248. if (newOptions.mutations) {
  249. options.mutations = newOptions.mutations
  250. }
  251. if (newOptions.getters) {
  252. options.getters = newOptions.getters
  253. }
  254. if (newOptions.modules) {
  255. for (var key in newOptions.modules) {
  256. options.modules[key] = newOptions.modules[key]
  257. }
  258. }
  259. resetStore(this)
  260. };
  261. Store.prototype.onActionsResolved = function onActionsResolved (cb) {
  262. Promise.all(this._pendingActions).then(cb)
  263. };
  264. Store.prototype._withCommit = function _withCommit (fn) {
  265. var committing = this._committing
  266. this._committing = true
  267. fn()
  268. this._committing = committing
  269. };
  270. Object.defineProperties( Store.prototype, prototypeAccessors );
  271. function assert (condition, msg) {
  272. if (!condition) throw new Error(("[vuex] " + msg))
  273. }
  274. function resetStore (store) {
  275. store._actions = Object.create(null)
  276. store._mutations = Object.create(null)
  277. store._wrappedGetters = Object.create(null)
  278. var state = store.state
  279. // init root module
  280. installModule(store, state, [], store._options, true)
  281. // init all runtime modules
  282. Object.keys(store._runtimeModules).forEach(function (key) {
  283. installModule(store, state, key.split('.'), store._runtimeModules[key], true)
  284. })
  285. // reset vm
  286. resetStoreVM(store, state)
  287. }
  288. function resetStoreVM (store, state) {
  289. var oldVm = store._vm
  290. // bind store public getters
  291. store.getters = {}
  292. var wrappedGetters = store._wrappedGetters
  293. var computed = {}
  294. Object.keys(wrappedGetters).forEach(function (key) {
  295. var fn = wrappedGetters[key]
  296. // use computed to leverage its lazy-caching mechanism
  297. computed[key] = function () { return fn(store); }
  298. Object.defineProperty(store.getters, key, {
  299. get: function () { return store._vm[key]; }
  300. })
  301. })
  302. // use a Vue instance to store the state tree
  303. // suppress warnings just in case the user has added
  304. // some funky global mixins
  305. var silent = Vue.config.silent
  306. Vue.config.silent = true
  307. store._vm = new Vue({
  308. data: { state: state },
  309. computed: computed
  310. })
  311. Vue.config.silent = silent
  312. // enable strict mode for new vm
  313. if (store.strict) {
  314. enableStrictMode(store)
  315. }
  316. if (oldVm) {
  317. // dispatch changes in all subscribed watchers
  318. // to force getter re-evaluation.
  319. store._withCommit(function () {
  320. oldVm.state = null
  321. })
  322. Vue.nextTick(function () { return oldVm.$destroy(); })
  323. }
  324. }
  325. function installModule (store, rootState, path, module, hot) {
  326. var isRoot = !path.length
  327. var state = module.state;
  328. var actions = module.actions;
  329. var mutations = module.mutations;
  330. var getters = module.getters;
  331. var modules = module.modules;
  332. // set state
  333. if (!isRoot && !hot) {
  334. var parentState = getNestedState(rootState, path.slice(0, -1))
  335. var moduleName = path[path.length - 1]
  336. store._withCommit(function () {
  337. Vue.set(parentState, moduleName, state || {})
  338. })
  339. }
  340. if (mutations) {
  341. Object.keys(mutations).forEach(function (key) {
  342. registerMutation(store, key, mutations[key], path)
  343. })
  344. }
  345. if (actions) {
  346. Object.keys(actions).forEach(function (key) {
  347. registerAction(store, key, actions[key], path)
  348. })
  349. }
  350. if (getters) {
  351. wrapGetters(store, getters, path)
  352. }
  353. if (modules) {
  354. Object.keys(modules).forEach(function (key) {
  355. installModule(store, rootState, path.concat(key), modules[key], hot)
  356. })
  357. }
  358. }
  359. function registerMutation (store, type, handler, path) {
  360. if ( path === void 0 ) path = [];
  361. var entry = store._mutations[type] || (store._mutations[type] = [])
  362. entry.push(function wrappedMutationHandler (payload) {
  363. handler(getNestedState(store.state, path), payload)
  364. })
  365. }
  366. function registerAction (store, type, handler, path) {
  367. if ( path === void 0 ) path = [];
  368. var entry = store._actions[type] || (store._actions[type] = [])
  369. var dispatch = store.dispatch;
  370. var commit = store.commit;
  371. entry.push(function wrappedActionHandler (payload, cb) {
  372. var res = handler({
  373. dispatch: dispatch,
  374. commit: commit,
  375. getters: store.getters,
  376. state: getNestedState(store.state, path),
  377. rootState: store.state
  378. }, payload, cb)
  379. if (!isPromise(res)) {
  380. res = Promise.resolve(res)
  381. }
  382. if (store._devtoolHook) {
  383. return res.catch(function (err) {
  384. store._devtoolHook.emit('vuex:error', err)
  385. throw err
  386. })
  387. } else {
  388. return res
  389. }
  390. })
  391. }
  392. function wrapGetters (store, moduleGetters, modulePath) {
  393. Object.keys(moduleGetters).forEach(function (getterKey) {
  394. var rawGetter = moduleGetters[getterKey]
  395. if (store._wrappedGetters[getterKey]) {
  396. console.error(("[vuex] duplicate getter key: " + getterKey))
  397. return
  398. }
  399. store._wrappedGetters[getterKey] = function wrappedGetter (store) {
  400. return rawGetter(
  401. getNestedState(store.state, modulePath), // local state
  402. store.getters, // getters
  403. store.state // root state
  404. )
  405. }
  406. })
  407. }
  408. function enableStrictMode (store) {
  409. store._vm.$watch('state', function () {
  410. assert(store._committing, "Do not mutate vuex store state outside mutation handlers.")
  411. }, { deep: true, sync: true })
  412. }
  413. function isObject (obj) {
  414. return obj !== null && typeof obj === 'object'
  415. }
  416. function isPromise (val) {
  417. return val && typeof val.then === 'function'
  418. }
  419. function getNestedState (state, path) {
  420. return path.length
  421. ? path.reduce(function (state, key) { return state[key]; }, state)
  422. : state
  423. }
  424. function install (_Vue) {
  425. if (Vue) {
  426. console.error(
  427. '[vuex] already installed. Vue.use(Vuex) should be called only once.'
  428. )
  429. return
  430. }
  431. Vue = _Vue
  432. applyMixin(Vue)
  433. }
  434. // auto install in dist mode
  435. if (typeof window !== 'undefined' && window.Vue) {
  436. install(window.Vue)
  437. }
  438. var index = {
  439. Store: Store,
  440. install: install,
  441. mapState: mapState,
  442. mapMutations: mapMutations,
  443. mapGetters: mapGetters,
  444. mapActions: mapActions
  445. }
  446. return index;
  447. }));