vuex是一個專門爲vue.js應用程序開發的狀態管理模式,它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。html
vueX有幾個核心的概念:vue
Statees6
Gettersweb
Mutationsvue-router
Actionsvuex
Modulesvue-cli
首先咱們用vue-cli構建一個vue目錄,如圖所示npm
]json
其中有三個vue組件,app.vue,hello.vue,content.vue,在router目錄的index.js定義了路由關係。數組
import Vue from 'vue' import Router from 'vue-router' import Hello from '@/components/Hello' Vue.use(Router); export default new Router({ routes: [ { path: '/', name: 'Hello', component: Hello } ] })
APP.vue
<template> <div id="app"> <h1>{{ msg }}</h1> <router-view></router-view> </div> </template> <script> export default { name: 'app', data(){ return { msg: 'Welcome to Your App.vue components' } }, } </script>
hello.vue
<template> <div class="hello"> <h1>{{ msg }}</h1> <contents></contents> </div> </template> <script> import contents from './Content'; export default { name: 'hello', data () { return { msg: 'Welcome to Your Hello.vue components' } }, components:{ contents } } </script>
content.vue
<template> <div id="inner"> <h2>{{msg}}</h2> </div> </template> <script> export default{ name:'content', data(){ return { msg:'Welcome to Your Content.vue components' } } } </script>
經過上面的三個組件和路由咱們能夠看出,訪問跟路徑,app組件引入hello組件,hello.vue嵌套content.vue組件,跟main.js同級建一個store.js,定義vuex的store和簡單的mutations
import vue from 'vue'; import vuex from 'vuex'; vue.use(vuex); export default new vuex.Store({ state:{ time:new Data().getTime(), names:["張三"], } })
修改main.js,添加vuex的使用
import Vue from 'vue' import App from './App' import router from './router' import store from './store.js' new Vue({ el: '#app', router, store, template: '<App/>', components: { App } });
這個時候這個項目已經把 store 的實例注入全部的子組件,裏面有一個state對象和mutations對象,state包括了所有的狀態,做爲一個惟一數據源存在,vue項目裏面能夠在任意組件裏面引用state裏面的屬性,
經過 js {{ this.$store.state.time }}
能夠直接訪問store定義的state對象
在計算屬性中返回某個狀態
computed:{ count(){ return this.$store.state.time; } }
當一個組件獲取多個狀態,上面兩種使用方式比較重複和冗餘,爲了解決這個問題,咱們可使用mapState輔助函數
import {mapState} from 'vuex' export default { computed:mapState([ 'time' ]) }
mapState返回一個對象,映射this.count爲this.$store.state.time,mapState裏面參數是數組形式,參數名和state同名
import {mapState} from 'vuex' computed:mapState({ time:state=>state.time, nameArr:'names' })
這種方式的mapState形參是一個對象,第一個count使用箭頭函數,返回state.count,第二個修改了names的別名變成nameArr
咱們修改store.js,經過添加mutations,來改變store裏面的state。更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutations 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數
export default new vuex.Store({ state:{ time:new Date().getTime(), names:["張三"] }, mutations:{ pushName (state,thisName){ state.names.push(thisName.name) } } })
咱們修改app組件,
<label> <input type="text" v-model="addName" /> <button @click="addNameFn">添加</button> </label> <p>姓名: <span v-for="name in nameArr">{{ name }} </span> </p>
export default { name: 'app', data(){ return { msg: 'Welcome to Your App.vue components', addName:'' } }, computed:mapState({ nameArr:'names' }), methods:{ addNameFn(){ var that=this; this.$store.commit('pushName',{name:that.addName}) } } }
Mutations必須是同步函數,由於每一條 mutation 被記錄,devtools 都須要捕捉到前一狀態和後一狀態的快照。然而 mutation 在異步函數中的回調讓這不可能完成
調用方式有三種
使用this.$store.commit調用,第一個參數是Mutations裏面定義的方法名,第二個參數是傳入的形參,建議應該是一個對象,能夠包含多個字段,而且會更容易閱讀代碼
addNameFn(){ this.$store.commit('pushName',{ name:this.addName }) }
使用 type屬性對象,commit調用的參數只有一個是一個對象,type是Mutations裏面定義的方法名,其餘字段是形參
addNameFn(){ this.$store.commit({ type:'pushName', name:this.addName }) }
使用mapMutations,引入 mapMutations ,將methods 映射爲 store.commit 調用
import {mapMutations} from 'vuex' methods:{ ...mapMutations([ 'pushName' ]), addNameFn(){ this.pushName({name:that.addName}) } }
有時候咱們須要根據store中的state中的屬性派生一些值,例如統計添加的姓名總數,若是有多個組件須要用到統計姓名總數這個值,咱們要麼是在每一個組件中重複寫一個方法,要麼是
寫一個公用的方法,每一個組件引入,這兩種方法都不是很理想,因此引入了Getters,能夠認爲是store的計算屬性,首先添加getters,添加一個統計添加的姓名總數的方法,而且在每一個組件打印這個總數
修改store.js,添加getters屬性,添加getNameLen方法,參數是state
export default new vuex.Store({ state:{ time:new Date().getTime(), names:["張三"] }, mutations:{ pushName (state,thisName){ state.names.push(thisName.name) } }, getters:{ getNameLen:state=>{ return state.names.length } } })
修改App.vue的template,直接打印添加姓名的個數
<label> <input type="text" v-model="addName"/> <button @click="addNameFn">添加</button> </label> <p>姓名: <span v-for="name in nameArr">{{ name }} </span> </p> <p>人數:{{ this.$store.getters.getNameLen }}</p>
修改完這些,咱們發現當咱們添加一個姓名,每一個組件都會更新添加的姓名的總條數,getters調用就是這麼簡單,上面只是一種調用方式,除此外還有兩種調用方式
1.在計算屬性中引入
<p>人數:{{ getNameLen }}</p>
computed: { nameCount(){ return this.$store.getters.getNameLen } }
2.使用 mapGetters,引入mapGetters,使用個結構賦值的方法,將getters裏面的方法映射到局部計算屬性上,若是是數組則跟getters裏面的方法名同名,對象能夠修更名稱,同mapState同樣
<p>人數:{{ getNameLen }}</p>
import {mapGetters} from 'vuex' computed: { ...mapGetters([ "getNameLen" ]), ...mapState({ nameArr: 'names', }) }
Action相似於mutation,不一樣在於
action能夠包含異步操做,而mutation只能是同步的
mutation是直接修改state裏面的數據狀態,並且action是commit一個mutation來記錄修改狀態。
讓咱們經過一個簡單例子來實現一個簡單的action:
1.修改 config index.js,引入url模塊,修改dev配置裏面的proxyTable,建一個與src同級的static目錄,裏面放一個
getName-time0.json文件,模擬本地http請求返回的json數據,重啓服務, npm run dev
訪問 http://localhost:8080/dataweb/getName?time=0
就能請求到static裏面的json文件
url=require('url'); proxyTable: { '/dataweb': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: function(path, req) { var urlParsed = url.parse(req.url, true), query = urlParsed.query, pathname = urlParsed.pathname.replace(/\/*$/g,''); pathname = pathname.substring(pathname.lastIndexOf('/')); Object.keys(query).forEach((key) => { pathname += ('-' + key + query[key]); }); pathname = '/static' + pathname + '.json'; console.log('proxy request ' + path + ' to ' + pathname); return pathname; } } }
{ "data":["趙錢","王五","孫劉"] }
建立actions,修改store.js,引入vue-resource,actions是經過提交mutations來修改狀態,因此在mutations增長一個getNames方法
state裏面增長一個data字段記錄數據,actions增長一個getData方法。getDate有一個默認的context參數,這個參數具備跟store實例相同的屬性和方法
經過調用context.commit提交一個mutation,或者咱們能夠經過es6裏面的結構賦值傳入一個{commit},第二個參數 _param是咱們分發action傳入的參數
import Vue from 'vue'; import vuex from 'vuex'; import VueResource from 'vue-resource'; Vue.use(VueResource); Vue.use(vuex); export default new vuex.Store({ state:{ time:new Date().getTime(), data:[], names:["張三"] }, mutations:{ pushName (state,thisName){ state.names.push(thisName.name) }, getNames(state,data){ state.data=data.list; } }, getters:{ getNameLen:state=>{ return state.names.length } }, actions:{ getData({ commit },_param){ return Vue.http.get('/dataweb/getName',{ params:_param.data }).then((respons)=>{ commit({ type:'getNames', list:respons.data }); }) } } })
修改app.vue組件,template裏面增長一個按鈕
<button @click="searchName">顯示所有姓名</button> <p><span v-for="values in nameData">{{ values }} </span></p>
data數據裏面增長一個_data存儲數據,methods裏面增長一個searchName方法,派發getDate事件,而且傳入data參數,actions
的方法返回的promise,能夠被store.dispatch
處理,而且store.dispatch
仍舊返回一個promise
getData裏面的promise返回成功則更新this._data數據,失敗則輸出獲取數據失敗
data(){ return { msg: 'Welcome to Your App.vue components', addName: '', nameData:[], } }, methods: { searchName(){ this.$store.dispatch({ type:'getData', data:{ time:0 } }).then(()=>{ this.nameData=this.$store.state.data },()=>{ console.log('獲取數據失敗') }) } }
從上面的例子咱們瞭解到,點擊一個按鈕發生了這些操做;
定義一個getData的action 異步調用一個請求,請求成功,commit一個getNames的mutations,修改state的data數據
執行searchName事件,用$store.dispatch
派發一個getData
的actions,而且傳入data:{time:0}
的參數
dispatch返回的promise成功,就表示getDate裏面的commit已經執行完畢,state.data已經有數據,更新當前this._nameData,循環輸出數據
在methods派發action除了實例的這種以對象形式派發,還有三種
以載荷方式
this.$store.dispatch('increment',{ data:{ time:1 } })
在methods裏面使用 mapActions 方式 映射action
import {mapActions} from 'vuex'; //數組形式 調用直接this.getDate ...mapActions([ 'getData' ]), //對象形式 this.searchName 等同於 this.getData ...mapActions({ searchName:'getData' })
修改methods裏面的searchName方法
searchName(){ this.getDate({ data:{ time:0 } }).then(()=>{ this.nameData=this.$store.state.data },()=>{ console.log('數據失敗') }) }
vuex還有一個Modules概念,本篇文章就介紹這麼多了,等學習完modules,在補充。。。。。