1
0

vuex.js 14 KB

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