1.1 vuex簡介
官網:https://vuex.vuejs.org/zh/guide/
參考博客:https://www.cnblogs.com/first-time/p/6815036.html
1、什么是Vuex?
1. 官方說法:Vuex 是一個專為 Vue.js應用程序開發的狀態管理模式。
2. 它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
3. 個人理解:Vuex是用來管理組件之間通信的一個插件
2、vuex作用
1. 我們知道組件之間是獨立的,組件之間想要實現通信,我目前知道的就只有props選項,但這也僅限於父組件和子組件之間的通信。
2. 如果兄弟組件之間想要實現通信呢?當做中大型項目時,面對一大堆組件之間的通信,還有一大堆的邏輯代碼,會不會很抓狂??
3. 那為何不把組件之間共享的數據給“拎”出來,在一定的規則下管理這些數據呢? 這就是Vuex的基本思想了。
總結:使用vuex作用就是實現組件間數據共享
3、vuex原理
1. vue團隊為了簡化組件間的通信,將state抽象成一個單例模式,將其放到全局,讓各個組件都能共享使用
2. vuex數據傳遞是單向的:action ---> mutation ---> state ---> component ---> action
vue component指的就是我門定義的組件
action 交互中產生的動作
mutations 動作產生的修改數據的行為
state 共享數據
3. vuex設計的時候相對修改的行為做單測(測試),開發了devtools來做測試,只能檢測同步的操作
4. 規范定義:只能在mutations中做同步操作,所以增加了action來異步處理數據
5. 將mutations中的異步操作轉移到actions中了,這樣就可以測試同步的操作了
4、vuex使用場景
1. 如果您需要構建一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇。
2. 如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗余的。
5、vuex流程圖
1、vue組件(Vue Components)會 發出(Dispatch)一些動作(Actions)
2、動作會 提交(Commit)一個對數據的改變(Mutations)
3、提交的改變數據存放在 狀態(State) 中的
4、最后 State將改變的數據再 渲染(Render)到組件(Vue Components),展示被改變后的數據
1.2 vuex使用(vuex使用分為以下兩步)
1、第一步:實例化一個store
注:vuex.store用來創建store,參數對象中,可以定義各個模塊
1. state定義狀態模塊(存儲數據的),存放組件之間共享的數據
2. getters定義動態的數據,類似組件中的computed動態數據
3. mutations:定義改動states的動作行為,類似觀察者模式中的訂閱事件on
4. action:定義這些交互動作(異步),類似觀察者模式中的訂閱事件方法on(只不過是用來處理異步的)
2、第二步:在vue實例化對象中,注冊store
1. 將第一步的實例化對象注冊進來,注冊路由后,組件實例化對象有了$route屬性對象
2. 注冊store,組件實例化對象有了$store屬性對象,這個store對象有下面這些方法
$.store.commit用來觸發mutations訂閱的消息
$.store.dispatch用來觸發action訂閱的消息的
$.store.state使用狀態中的數據

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <h1 @click="$store.commit('reduce', 20);">vue實例化對象:點擊減20</h1> <h2 @click="$store.dispatch('dealNum', 10, 20, 30)">更新數據:將num兩秒后重置為:10</h2> <h1>state中的數據 {{$store.state.num}}</h1> <h2>雙倍num {{$store.getters.doubleNum}}</h2> <router-view></router-view> <!-- 定義渲染的容器 --> </div> <template id="home"> <div> <h1 @click="$store.commit('add', 10, 'hello')">home:點擊加10</h1> <h2>home組件中 {{$store.state.num}}</h2> <router-view></router-view> <!-- 第一步 定義子路由渲染的容器 --> </div> </template> <script type="text/javascript" src="vue.js"></script> <script type="text/javascript" src="vue-router.js"></script> <script type="text/javascript" src="vuex.js"></script> <script type="text/javascript"> // 定義組件 var Home = { template: '#home' }; // 第一步 定義路由規則 var routes = [ { path: '/home', name: 'home', component: Home } ]; // 定義store第一步 定義store實例化對象 var store = new Vuex.Store({ state: { // 定義狀態 num: 0 }, getters: { // 定義動態綁定的數據 doubleNum: function(state) { return state.num * 2; } }, mutations: { // 修改的消息 add: function(state, num) { // 增加num值 state.num += num; }, reduce: function(state, num) { // 減少num值 state.num -= num; }, resetNum: function(state, num) { state.num = num; } }, actions: { // 定義actions dealNum: function(context, num) { setTimeout(function() { // 我們可以異步提交 context.commit('resetNum', num) }, 2000) } } }); // 第二步 實例化路由對象 var router = new VueRouter({ routes: routes // 定義路由規則 }); // 第三步 注冊路由 和 store對象 var app = new Vue({ el: '#app', // 注冊路由 router: router, store: store // 使用vuex第二步 注冊store }) </script> </body> </html>
1.3 vuex基本用法
1、初始化環境
vue init webpack-simple vuex-demo
cd vuex-demo
npm install
cnpm install vuex -S # 安裝vuex
npm run dev
2、在main.js中導入並配置store.選項(創建 sre/store.js文件,可以是一個空文件)
1. 在main.js中導入 store對象: import store from './store'
2. 配置store選項后,vue就會自動將store對象注入到所有子組件中,在子組件中通過this.$store 訪問store對象

import Vue from 'vue' import App from './App.vue' import store from './store' // 導入store對象 new Vue({ store, // 配置store選項后,指定為store對象,vue就會自動將store對象注入到所有子組件中 // 在子組件中通過this.$store 訪問store對象 el: '#app', render: h => h(App) });
3、編輯store.js文件
注1:Vuex的核心是Store(倉庫),相當於是一個容器,一個store實例中包含以下屬性的方法:
注2:不能直接修改數據,必須顯式提交變化,目的是為了追蹤到狀態的變化
1) state 定義屬性(狀態、數據)
2) getters 用來獲取屬性
3) actions 定義方法(動作)
4) commit 提交變化,修改數據的唯一方式就是顯式的提交mutations
5) mutations 定義變化

/** * vuex配置:store.js **/ import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); //1、定義屬性(數據) var state = { count:6 }; //2、定義gettters獲取屬性:在App.vue中使用 輔助函數 訪問 vuex 組件中數據調用此函數 var getters={ count(state){ return state.count; } }; //3、定義actions提交變化:其他組件中調用的方法() const actions = { increment({commit,state}){ // context包含屬性(函數):commit,dispatch,state if(state.count<10){ // 當count數值小於10才會提交改變(大於10就不增加了) commit('increment'); } // 1、commit提交改變(不能直接修改數據) // 2、commit中的參數 'increment' 是自定義的,可以認為是類型名 // 3、commit提交的改變會給 mutations } }; //4、定義mutations定義變化,處理狀態(數據的改變) const mutations={ increment(state){ state.count++; } }; // 創建一個store對象(對象里定義需要導出的變量) const store=new Vuex.Store({ state, getters, actions, mutations, }); // 導出store對象 export default store;
4、 編輯App.vue
1. 在子組件中訪問store對象的兩種方式
方式1:通過this.$store訪問
方式2:通過輔助函數:mapState、mapGetters、mapActions 訪問,vuex提供了兩個方法
mapState 獲取state
mapGetters 獲取getters(獲取屬性:數據)
mapActions 獲取actions(獲取方法:動作)

<template> <div id="app"> <button @click="increment">增加</button> <button>減小</button> <p>當前數字為:{{count}}</p> </div> </template> <script> import {mapGetters,mapActions} from 'vuex' export default { name: 'app', data () { return { msg: 'Welcome to Your Vue.js App' } }, // 方式二:使用 輔助函數 訪問 vuex 組件中數據 computed:mapGetters([ // 這里定義一個數組,數組中指定要從vuex中獲取的屬性 'count', // 這里的count就是 store.js中getters定義的屬性 ]), methods:mapActions([ // 這里定義一個數組,數組中指定要從vuex中獲取的方法 'increment' // 這里的increment就是 store.js中actions定義的函數 ]) // // 方式一:通過this.$store訪問vuex組件中的數據 // computed:{ // count(){ // return this.$store.state.count; // } // } } </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; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
5、效果圖
6、異步操作

import Vue from 'vue' import App from './App.vue' import store from './store' // 導入store對象 new Vue({ store, // 配置store選項后,指定為store對象,vue就會自動將store對象注入到所有子組件中 // 在子組件中通過this.$store 訪問store對象 el: '#app', render: h => h(App) });

/** * vuex配置:store.js **/ import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); //1、定義屬性(數據) var state = { count:6 }; //2、定義gettters獲取屬性:在App.vue中使用 輔助函數 訪問 vuex 組件中數據調用此函數 var getters={ count(state){ return state.count; } }; //3、定義actions提交變化:其他組件中調用的方法() const actions = { increment({commit,state}){ // context包含屬性(函數):commit,dispatch,state if(state.count<10){ // 當count數值小於10才會提交改變(大於10就不增加了) commit('increment'); } // 1、commit提交改變(不能直接修改數據) // 2、commit中的參數 'increment' 是自定義的,可以認為是類型名 // 3、commit提交的改變會給 mutations }, /** 定義異步操作 **/ incrementAsyn({commit,state}){ var p=new Promise((resolve,reject) => { // 異步操作 setTimeout(() => { resolve() },3000) }); p.then(() => { // 上面執行完成后才執行 p.then() commit('increment'); }).catch(() => { // 異常處理 console.log('異步操作失敗') }) } }; //4、定義mutations定義變化,處理狀態(數據的改變) const mutations={ increment(state){ state.count++; } }; // 創建一個store對象(對象里定義需要導出的變量) const store=new Vuex.Store({ state, getters, actions, mutations, }); // 導出store對象 export default store;

<template> <div id="app"> <button @click="increment">增加</button> <button @click="incrementAsyn">異步增加</button> <p>當前數字為:{{count}}</p> </div> </template> <script> import {mapGetters,mapActions} from 'vuex' export default { name: 'app', data () { return { msg: 'Welcome to Your Vue.js App' } }, // 方式二:使用 輔助函數 訪問 vuex 組件中數據 computed:mapGetters([ // 這里定義一個數組,數組中指定要從vuex中獲取的屬性 'count', // 這里的count就是 store.js中getters定義的屬性 ]), methods:mapActions([ // 這里定義一個數組,數組中指定要從vuex中獲取的方法 'increment', // 這里的increment就是 store.js中actions定義的函數 'incrementAsyn' // 異步提交 ]) } </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; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
1.4 分模塊組織Vuex
1、初始化環境
vue init webpack-simple vuex-demo2
cd vuex-demo2
npm install
cnpm install vuex -S # 安裝vuex
npm run dev
2、Vuex模塊化結構

|-src |-main.js // 項目入口文件 |-App.vue |-store |-index.js // 我們組裝模塊並導出 store 的地方 |-getters.js // 公共的 getters (用來獲取公共屬性) |-actions.js // 根級別的 action (提交公共改變) |-mutations.js // 根級別的 mutation (處理狀態,數據的改變) |-types.js // 定義類型常量(commit中提交的常量) |-modules //分為多個模塊,每個模塊都可以擁有自己的state、getters、actions、mutations |-user.js // 用戶模塊(這里僅以user模塊作為事例)
3、代碼事例

import Vue from 'vue' import App from './App.vue' import store from './store/index.js' new Vue({ store, el: '#app', render: h => h(App) });

<template> <div id="app"> <button @click="increment">增加</button> <button @click="decrement">減小</button> <button @click="incrementAsync">增加</button> <p>當前數字為:{{count}}</p> <p>{{isEvenOrOdd}}</p> </div> </template> <script> import {mapState,mapGetters,mapActions} from 'vuex' export default { name: 'app', data () { return { msg: 'Welcome to Your Vue.js App' } }, computed:mapGetters([ 'count', 'isEvenOrOdd' ]), methods:mapActions([ 'increment', 'decrement', 'incrementAsync' ]) } </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; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>

import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); import getters from './getters.js' import actions from './actions.js' import user from './modules/user.js' export default new Vuex.Store({ getters, actions, modules:{ user } });

const getters={ isEvenOrOdd(state){ return state.user.count%2==0?'偶數':'奇數'; // user模塊中的count } }; export default getters;

import types from './types.js' const actions={ incrementAsync({commit,state}){ //異步操作 var p=new Promise((resolve,reject) => { setTimeout(() => { resolve(); },3000); }); p.then(() => { commit(types.INCREMENT); }).catch(() => { console.log('異步操作'); }); } }; export default actions;

/** * 定義類型常量 */ const INCREMENT='INCREMENT'; const DECREMENT='DECREMENT'; export default { INCREMENT, DECREMENT }

/** * 用戶模塊 */ import types from '../types.js' const state={ count:6 }; var getters={ count(state){ return state.count; } }; const actions = { increment({commit,state}){ commit(types.INCREMENT); //提交一個名為increment的變化,名稱可自定義,可以認為是類型名 }, decrement({commit,state}){ if(state.count>10){ commit(types.DECREMENT); } } }; const mutations={ [types.INCREMENT](state){ // ES6中中括號里表示 變量 state.count++; }, [types.DECREMENT](state){ state.count--; } }; export default { state, getters, actions, mutations }
4、項目結構
5、簡化版

import Vue from 'vue' import App from './App.vue' import store from './store/index' new Vue({ store, el: '#app', render: h => h(App) })

<template> <div id="app"> <h1>app</h1> <p>數據:{{count}}</p> <p @click="increment">增加</p> </div> </template> <script> import {mapGetters, mapActions} from 'vuex' export default { name: 'app', data () { return { msg: 'Welcome to Your Vue.js App' } }, computed:mapGetters([ 'count', ]), methods:mapActions([ 'increment' ]) } </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; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>

import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); // import getters from './getters.js' // import actions from './actions.js' import user from './modules/user.js' export default new Vuex.Store({ // getters, // actions, modules:{ user } });

//1、定義屬性(數據) var state = { count:6 }; //2、定義gettters獲取屬性:在App.vue中使用 輔助函數 訪問 vuex 組件中數據調用此函數 var getters = { count(state){ return state.count } }; //3、定義actions提交變化:其他組件中調用的方法() var actions = { increment({commit,state}){ commit('increment') } }; //4、定義mutations定義變化,處理狀態(數據的改變) var mutations = { increment(state){ state.count++ } }; //5、導出store對象 export default { state, getters, actions, mutations }