Vuex是一個專爲Vue.js應用程序開發的狀態管理模式。當項目比較龐大的時候,每一個組件的狀態不少,爲了方便管理,須要把組件中的狀態抽取出來,放入Vuex中進行統一管理。javascript
每個 Vuex 應用的核心就是store(倉庫)。"store"基本上就是一個容器,它包含着你的應用中大部分的狀態(state)。Vuex 和單純的全局對象有如下兩點不一樣:vue
Vuex的狀態存儲是響應式的。當 Vue組件從store中讀取狀態的時候,若store中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。java
你不能直接改變store中的狀態。改變store中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。node
構建vue工程vue init webpack vuexStudy
構建後目錄結構
其中:
index.jswebpack
import Vue from 'vue' import Vuex from 'vuex' //若是在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex) Vue.use(Vuex); export default new Vuex.Store({ state: { //存放組件之間共享的數據 //在組件經過this.$store.state.count獲取 count: 0 }, mutations: { //顯式的更改state裏的數據,不能用於處理異步事件 //組件中經過this.$store.commit('incrementByStep');調用 incrementByStep(state) { state.count++; } }, getters:{ //如vue中的計算屬性同樣,基於state數據的二次包裝,經常使用於數據的篩選和多個數據的相關性計算 }, actions:{ //相似於mutation,用於提交mutation來改變狀態,而不直接變動狀態,能夠包含任意異步操做 } });
new Vuex.Store({}) 表示建立一個Vuex實例,一般狀況下,他須要注入到Vue實例裏。 Store是Vuex的一個核心方法,字面上理解爲「倉庫」的意思。Vuex Store是響應式的,當Vue組件從store中讀取狀態(state選項)時,若store中的狀態發生更新時,他會及時的響應給其餘的組件並且不能直接改變store的狀態,改變狀態的惟一方法是顯式地提交更改。git
main.js引入vuexgithub
import Vue from 'vue' import App from './App' //vuex文件 import store from './store' Vue.config.productionTip = false; /* eslint-disable no-new */ new Vue({ el: '#app', //引入 store, components: { App }, template: '<App/>' })
APP.vue引用了counter這個組件web
<div id="app"> <!--<img src="./assets/logo.png">--> <!--<HelloWorld/>--> <counter/> </div> </template> <script> import HelloWorld from './components/HelloWorld' import counter from './components/counter' export default { name: 'App', components: { //HelloWorld counter } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
counter.vue定義counter組件vuex
<template> <div id="counterContent"> <div>{{ count }}</div> <button v-on:click="addCount">請點擊</button> </div> </template> <script> export default { name: "counter", computed: { count () { return this.$store.state.count } }, methods:{ addCount(){ debugger; this.$store.commit('incrementByStep'); } } } </script> <style scoped> #counterContent{ background-color: blue; width:200px; height:50px; } </style>
經過npm run dev
啓動項目,最終的結果如圖:
npm
node添加Vuex依賴下載的vuex文件(node_modules目錄下)以下:
其中vuex.common.js在預編譯調試時,CommonJS規範的格式,可使用require("")引用的NODEJS格式。
vuex.esm.js在預編譯調試時, EcmaScript Module(ES MODULE),支持import from 最新標準的。
vuex.js直接用在<script>標籤中的,完整版本,直接就能夠經過script引用。
而vuex的源碼託管在https://github.com/vuejs/vuex,這裏研究git上的源碼。
Vuex 源碼的入口是 src/index.js。
import { Store, install } from './store' import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers' export default { Store, install, version: '__VERSION__', mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers }
這是Vuex對外暴露的API。其中, Store是Vuex提供的狀態存儲類,一般咱們使用Vuex就是經過建立 Store的實例。接着是install方法,這個方法一般是咱們編寫第三方Vue插件的時候使用。
install是在store.js內暴露的方法
當Vue經過npm安裝到項目中的時候,咱們在代碼中引入第三方Vue插件須要添加下列代碼
import Vue from 'vue' import Vuex from 'vuex' //若是在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex) Vue.use(Vuex);
執行Vue.use(Vuex)的時候,其實就是調用了install的方法並傳入Vue的引用。
Vue.use
Vue.use = function (plugin) { var installedPlugins = (this._installedPlugins || (this._installedPlugins = [])); if (installedPlugins.indexOf(plugin) > -1) { return this } // additional parameters var args = toArray(arguments, 1); args.unshift(this); if (typeof plugin.install === 'function') { //調用vuex的install plugin.install.apply(plugin, args); } else if (typeof plugin === 'function') { plugin.apply(null, args); } installedPlugins.push(plugin); return this }; }
install
//判斷Vue是否已存在,保證install方法只執行一次 if (Vue && _Vue === Vue) { if (process.env.NODE_ENV !== 'production') { console.error( '[vuex] already installed. Vue.use(Vuex) should be called only once.' ) } return } //賦值給Vue變量,index.js文件的其它地方使用Vue這個變量 Vue = _Vue //調用了 applyMixin 方法,給 Vue 的實例注入一個 $store 的屬性 applyMixin(Vue) }
plugin參數:
args參數:
var applyMixin = function (Vue) { //獲取版本信息,這裏是2 var version = Number(Vue.version.split('.')[0]); if (version >= 2) { //調用vuexInit Vue.mixin({ beforeCreate: vuexInit }); } else { var _init = Vue.prototype._init; Vue.prototype._init = function (options) { if ( options === void 0 ) options = {}; options.init = options.init ? [vuexInit].concat(options.init) : vuexInit; _init.call(this, options); }; } //給Vue實例注入$store 的屬性,能夠經過this.$store.xxx訪問 function vuexInit () { var options = this.$options; // store injection if (options.store) { this.$store = typeof options.store === 'function' ? options.store() : options.store; } else if (options.parent && options.parent.$store) { this.$store = options.parent.$store; } } };