【貓帶你上雲】Vuex入門小demo(呆萌)

SPA單頁面組件的開發中VueVuexReactRedux 都統稱爲同一狀態管理
個人的理解是全局狀態管理更合適
簡單的理解就是你在state中定義了一個數據之後,你可以在所在項目中的任何一個組件裏進行獲取、進行修改,並且你的修改可以得到全局的響應變更

什麼是Vuex?

官方說法:Vuex 是一個專爲 Vue.js應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

個人理解:Vuex是用來管理組件之間通信的一個插件

爲什麼要用Vuex?

我們知道組件之間是獨立的,組件之間想要實現通信
我目前知道的就只有props選項,但這也僅限於父組件和 子組件之間的通信

如果兄弟組件之間想要實現通信呢?嗯…,方法也有,但是實現就比較麻煩了
這和現代框架理論(讓我們程序猿把重心都放在業務邏輯的實現上)相違背
拋開怎麼實現的問題,試想一下,當做中大型項目時,面對一大堆組件之間的通信,還有一大堆的邏輯代碼,會不會很抓狂??
那爲何不把組件之間共享的數據給“拎”出來,在一定的規則下管理這些數據呢?

這就是Vuex的產生的意義和基本思想了

怎麼使用Vuex?

話不多說,我們先上代碼!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<script src="./js/vuex.js"></script>
<script src="./js/vue2.0.js"></script>
<body>
    <div id="app">
        
    </div>
</body>
<script>
	//在創建Vue實例之前
   Vue.use(Vuex);
   var myStore =  new Vuex.Store({
        state:{
            //存放組件之間共享的數據
            name:"jjk"
        },
		getters:{
		   //獲取數據的方法
		},
		mutations:{
		   //顯式的更改state裏的數據
		},
		actions:{
		   //
		}
    });
    new Vue({
        el:"#app",
        data:{
            name:"dk"
        },
        // 註冊store,到vue實例上
        store:myStore,
        mounted:function(){
            console.log(this)//控制檯
        }
    })
</script>
</html>

先解釋上面代碼的意思:

new Vuex.Store({}) 

表示創建一個Vuex實例,通常情況下,他需要注入到Vue實例裏

Store是Vuex的一個核心方法,字面上理解爲“倉庫”的意思。

Vuex Store是響應式的,當Vue組件從store中讀取狀態(state選項)時,

若store中的狀態發生更新時,他會及時的響應給其他的組件(類似雙向數據綁定),

而且不能直接改變store的狀態,

改變狀態的唯一方法就是,顯式地提交更改(mutations選項)
  • 那如何獲取到state的數據呢?

一般會在組件的計算屬性(computed)獲取state的數據
因爲,計算屬性會監控數據變化,一旦發生改變就會響應(重新計算)

// 在剛剛的頁面,我們再創建一個全局組件
Vue.component('hello',{
    template:"<p>{{name}}</p>",
    computed: {
        name:function(){
            return this.$store.state.name
        }
    },
     mounted:function(){
        console.log(this)
    }
})
  • Vuex有5個核心選項:
    • state
    • getters
    • mutations
    • actions
    • modules

state:用來存放組件之間共享的數據。他跟組件的data選項類似,只不過data選項是用來存放組件的私有數據。

getters:有時候,我們需要對state的數據進行篩選、過濾。
這些操作都是在組件的計算屬性進行的,如果多個組件需要用到篩選後的數據,那我們就必須到處重複寫該計算屬性函數;或者將其提取到一個公共的工具函數中,並將公共函數多處導入 - 兩者都不太理想。
如果把數據篩選完,再傳到計算屬性裏就不用那麼麻煩了,getters就是幹這個的
你可以把getters看成是store的計算屬性
getters下的函數接收接收state作爲第一個參數
如果getters對象有相應的方法,組件可以通過$store.getters對象.方法來獲取數據

mutations:前面講到的都是如何獲取state的數據,那如何把數據存儲到state中呢?在 Vuex store 中,實際改變 狀態(state) 的唯一方式是通過 提交(commit) 一個mutation
mutations下的函數接收state作爲參數,接收第二個參數payload(載荷),第二個參數是用來記錄開發者使用該函數的一些信息,比如說提交了什麼,提交的東西是用來幹什麼的,包含多個字段,所以載荷一般是對象(其實這個東西跟git的commit很類似)
還有一點需要注意:mutations方法必須是同步方法!

actions:既然mutations只能處理同步函數,我大js全靠‘異步回調’吃飯,怎麼能沒有異步,於是actions出現了…

  • actionsmutations的區別

      Actions 提交的是 mutations,而不是直接變更狀態。
      也就是說,actions會通過mutations,讓mutations幫他提交數據的變更。
    
      Action 可以包含任意異步操作。ajax、setTimeout、setInterval不在話下
    

modules: 因爲在大多數的項目中,我們對於全局狀態的管理並不僅僅一種情況的需求,有時有多方面的需求,比如寫一個商城項目,你所用到的全局state可能是關於購物車這一塊兒的也有可能是關於商品價格這一塊兒的;像這樣的情況我們就要考慮使用vuex中的 modules 模塊化了
具體怎麼使用modules呢?咱們在下面用vue-cli構建的小呆萌裏在仔細講

  • 總結:

各個類型的 API各司其職
mutation 只管存,你給我(dispatch)我就存
action只管中間處理,處理完我就給你,你怎麼存我不管
getter 我只管取,我不改的
action放在了 methods 裏面,說明我們應該把它當成函數來用(講道理,鉤子函數也應該可以的)
mutation是寫在store裏面的,這說明,它就是個半成品,中間量,我們不應該在外面去操作它。
getter寫在了 computed 裏面,這說明雖然 getter我們寫的是函數,但是我們應該把它當成計算屬性來用

上面都是對Vuex的基礎入門理論介紹比較多,下面我們使用vue-cli構建一個小呆萌,玩一玩 Vuex

使用 vue-cli 構建項目,並使用 Vuex

下面咱們一步一步地剖析下vuex的使用:

首先要安裝、使用 vuex

首先在 vue 2.0+ 你的vue-cli項目中安裝 vuex :

npm install vuex --save

然後 在src文件目錄下新建一個名爲store的文件夾,爲方便引入並在store文件夾裏新建一個index.js,裏面的內容如下:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store();
 
export default store;

接下來,在 main.js裏面引入store,然後再全局注入一下,這樣一來就可以在任何一個組件裏面使用this.$store了:

import store from './store'//引入store
 
new Vue({
  el: '#app',
  router,
  store,//使用store
  template: '<App/>',
  components: { App }
})

說了上面的前奏之後,接下來就是納入正題了,就是開篇說的state的玩法。回到store文件的index.js裏面,我們先聲明一個state變量,並賦值一個空對象給它,裏面隨便定義兩個初始屬性值;然後再在實例化的Vuex.Store裏面傳入一個空對象,並把剛聲明的變量state仍裏面:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 const state={//要設置的全局訪問的state對象
     showFooter: true,
     changableNum:0
     //要設置的初始屬性值
   };
 const store = new Vuex.Store({
       state
    });
 
export default store;

實際上做完上面的三個步驟後,你已經可以用this.store.state.showFooterthis.store.state.showFooter或this.store.state.changebleNum在任何一個組件裏面獲取showfooter和changebleNum定義的值了,但這不是理想的獲取方式;vuex官方API提供了一個getters,和vue計算屬性computed一樣,來實時監聽state值的變化(最新狀態),並把它也仍進Vuex.Store裏面,具體看下面代碼:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 const state={   //要設置的全局訪問的state對象
     showFooter: true,
     changableNum:0
     //要設置的初始屬性值
   };
const getters = {   //實時監聽state值的變化(最新狀態)
    isShow(state) {  //方法名隨意,主要是來承載變化的showFooter的值
       return state.showFooter
    },
    getChangedNum(){  //方法名隨意,主要是用來承載變化的changableNum的值
       return state.changebleNum
    }
};
const store = new Vuex.Store({
       state,
       getters
});
export default store;

光有定義的state的初始值,不改變它不是我們想要的需求,接下來要說的就是mutations了,mutattions也是一個對象,這個對象裏面可以放改變state的初始值的方法,具體的用法就是給裏面的方法傳入參數state或額外的參數,然後利用vue的雙向數據驅動進行值的改變,同樣的定義好之後也把這個mutations扔進Vuex.Store裏面,如下:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 const state={   //要設置的全局訪問的state對象
     showFooter: true,
     changableNum:0
     //要設置的初始屬性值
   };
const getters = {   //實時監聽state值的變化(最新狀態)
    isShow(state) {  //承載變化的showFooter的值
       return state.showFooter
    },
    getChangedNum(){  //承載變化的changebleNum的值
       return state.changableNum
    }
};
const mutations = {
    show(state) {   //自定義改變state初始值的方法,這裏面的參數除了state之外還可以再傳額外的參數(變量或對象);
        state.showFooter = true;
    },
    hide(state) {  //同上
        state.showFooter = false;
    },
    newNum(state,sum){ //同上,這裏面的參數除了state之外還傳了需要增加的值sum
       state.changableNum+=sum;
    }
};
 const store = new Vuex.Store({
       state,
       getters,
       mutations
});
export default store;

這時候你完全可以用 this.store.commit(show)this.store.commit(&#x27;show&#x27;) 或 this.store.commit(‘hide’) 以及 this.store.commit(newNum,6)showfooterchangebleNumVuexmutationsthis.store.commit(&#x27;newNum&#x27;,6) 在別的組件裏面進行改變showfooter和changebleNum的值了,但這不是理想的改變值的方式;因爲在 Vuex 中,mutations裏面的方法 都是同步事務,意思就是說:比如這裏的一個this.store.commit(‘newNum’,sum)方法,兩個組件裏用執行得到的值,每次都是一樣的,這樣肯定不是理想的需求

好在vuex官方API還提供了一個actions,這個actions也是個對象變量,最大的作用就是裏面的Action方法 可以包含任意異步操作,這裏面的方法是用來異步觸發mutations裏面的方法,actions裏面自定義的函數接收一個context參數和要變化的形參,context與store實例具有相同的方法和屬性,所以它可以執行context.commit(’ '),然後也不要忘了把它也扔進Vuex.Store裏面:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 const state={   //要設置的全局訪問的state對象
     showFooter: true,
     changableNum:0
     //要設置的初始屬性值
   };
const getters = {   //實時監聽state值的變化(最新狀態)
    isShow(state) {  //承載變化的showFooter的值
       return state.showFooter
    },
    getChangedNum(){  //承載變化的changebleNum的值
       return state.changableNum
    }
};
const mutations = {
    show(state) {   //自定義改變state初始值的方法,這裏面的參數除了state之外還可以再傳額外的參數(變量或對象);
        state.showFooter = true;
    },
    hide(state) {  //同上
        state.showFooter = false;
    },
    newNum(state,sum){ //同上,這裏面的參數除了state之外還傳了需要增加的值sum
       state.changableNum+=sum;
    }
};
 const actions = {
    hideFooter(context) {  //自定義觸發mutations裏函數的方法,context與store 實例具有相同方法和屬性
        context.commit('hide');
    },
    showFooter(context) {  //同上註釋
        context.commit('show');
    },
    getNewNum(context,num){   //同上註釋,num爲要變化的形參
        context.commit('newNum',num)
     }
};
  const store = new Vuex.Store({
       state,
       getters,
       mutations,
       actions
});
export default store;

而在外部組件裏進行全局執行actions裏面方法的時候,你只需要用執行

this.$store.dispatch(‘hideFooter’)

或this.$store.dispatch(‘showFooter’)

以及this.$store.dispatch(‘getNewNum’,6) //6要變化的實參

這樣就可以全局改變改變showfooter或changebleNum的值了,如下面的組件中,需求是跳轉組件頁面後,根據當前所在的路由頁面進行隱藏或顯示頁面底部的tabs選項卡

<template>
  <div id="app">
    <router-view/>
    <FooterBar v-if="isShow" />
  </div>
</template>

<script>
import FooterBar from '@/components/common/FooterBar'
import config from './config/index'
export default {
  name: 'App',
  components:{
    FooterBar:FooterBar
  },
  data(){
    return {
    }
  },
  computed:{
     isShow(){
       return this.$store.getters.isShow;
     }
  },
  watch:{
      $route(to,from){ //跳轉組件頁面後,監聽路由參數中對應的當前頁面以及上一個頁面
          console.log(to)
        if(to.name=='book'||to.name=='my'){ // to.name來獲取當前所顯示的頁面,從而控制該顯示或隱藏footerBar組件
           this.$store.dispatch('showFooter') // 利用派發全局state.showFooter的值來控制        
		} else {
           this.$store.dispatch('hideFooter')
        }
      }
  }
}
</script>

至此就可以做到一呼百應的全局響應狀態改變了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章