vuex的超詳細講解和具體使用細節記錄(篇幅略長,建議收藏)

什麼是vuex

官方定義

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

初學vuex,讀完這段官方定義之後,黑人問號,感受每一個字都認識,可是合在一塊了,好像就不理解了。好叭,讓咱們用大白話翻譯一下。補充:官方文檔定義一個概念的時候,的確是要作到表述凝練簡潔,因此就會出現這樣的定義概念略有晦澀的狀況

大白話講解

  • Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式vue

    vuex是爲vue.js項目開發的一個插件(包),這個插件(包)主要就是用來作狀態管理的。vuex

    問:什麼是狀態管理,狀態管理就管理狀態的(好像是廢話),其實在開發中,有一個比較常聽到的詞就是狀態,何爲狀態?咱們知道燈泡開和關分別是一種固定狀態,咱們可用1表明開,0表明關。這樣的話,用數字就能夠表明狀態了,那反過來講,狀態就是數據的具體表現形式,因此咱們能夠這樣理解:狀態管理就是數據管理,進一步而言,vuex就是去管理vue中的數據的npm

  • 它採用集中式存儲管理應用的全部組件的狀態後端

    魯迅說:vue是組件化開發,就是把一個頁面拆分紅一小塊一小塊。每一小塊都要有本身的數據用來呈現。好比下拉框有下拉框供選擇的數據,表格有表格要呈現的數據。那麼這些數據能夠直接放在.vue文件中的data裏面去管理,可是若是是大項目的話,數據放在.vue中的data去管理略有欠缺。因此:可使用vuex去統一存放管理各個組件的數據。vuex就像一個倉庫,用來存放組件中須要用到的數據,至於管理,就是增刪改查,往vuex中存取、修改、刪除等操做
  • 並以相應的規則保證狀態以一種可預測的方式發生變化數組

    這句話的意思就是,想要存取、修改、刪除vuex倉庫中的狀態數據,須要按照必定的語法規則,好比按照 action--> mutaion--> state的規則去增刪改查,好比使用輔助函數如增刪改查vuex中的數據。這個具體的規則下文中的vuex使用步驟中會逐一講解

因此vuex就是一個倉庫,用來存放數據的。因此咱們使用vuex通常會新建一個store文件夾,store單詞的中文意思就是商店、倉庫的意思框架

vuex的應用場景

  • 正常數據放到data裏面就好了,省得麻煩,通常小項目都不多用到vuex,畢竟vuex的步驟稍微多一點
  • 通常公共數據放到vuex中會比較好,畢竟組件有本身的data能夠存放數據,公共的變量如用戶信息、token等。vuex存一份,localstorage再存一份,取數據直接從vuex裏面取,取不到再從localstorage裏面去取。
  • 跨不少組件層級的數據通訊,也能夠經過vuex去作管理,畢竟vuex就像一個對象一個,好多組件都指向這個對象,當這個vuex對象發生了變化,全部的組件中對應的內容都會發生變化,這樣就能作到實時響應,一個變,你們都變

使用步驟

首先要搭建好項目,搭建項目的過程不贅述,項目搭建好了,咱們就能夠按照以下步驟使用vuex了

第一步 npm下載安裝vuex插件

由於vuex是特定的用來管理vue中的數據的一款插件,因此按照可插拔框架的思想,想要使用vuex就下載安裝,不想用的時候就卸載便可
npm install vuex --save異步

第二步 新建store文件夾註冊使用vuex插件

以下圖:
ide

把store對象掛載到vue對象上面的話,那麼每一個組件均可以訪問到這個store對象了,那麼每一個組件都能去使用vuex了

打印的vue實例對象以下圖

看一下$store的上具體內容


既然vue的總實例上掛載的vuex的$store對象中有咱們定義的state、mutations、actions、getters,那麼咱們經過this.$store...就能夠在各個組件上訪問、使用vuex中數據了。這麼一來,就驗證了vuex文檔中的那句話:vuex採用集中式存儲管理應用的全部組件的狀態是啊,都集中在vue實例上了,全部組件的狀態均可以訪問到了。模塊化

其實學習vuex就是學習兩點:

  1. 如何讀取vuex中倉庫的數據
  2. 如何修改vuex中倉庫的數據

第三步 讀取vuex中倉庫的數據

在上述代碼中,咱們已經在vuex中的state裏面定義了一個msg屬性,再貼一下代碼

export default new Vuex.Store({
    state:{
        msg:'我是vuex哦'
    },
    // 等...
})

接下來咱們在組件中使用這個數據,並呈如今頁面上

方式一 雙括號表達式直接使用(不推薦)

<h2>{{this.$store.state.msg}}</h2>
方式一不太優雅,通常不用,主要用方式二或方式三

方式二 mounted中去取用vuex中的數據

<template>
  <div class="box">
      <h2>{{msg}}</h2>
  </div>
</template>
<script>
export default {
    data() {
        return { msg:'' }
    },
    mounted() {
        this.msg = this.$store.state.msg
    },
}
</script>

方式三 使用computed去取vuex中的數據

<template>
  <div class="box">
      <h2>{{msg}}</h2>
  </div>
</template>
<script>
export default {
    computed: {
        msg(){ return this.$store.state.msg }
    }
}
</script>

第四步 修改vuex中的數據

通常是在事件的回調函數中去修改vuex中的數據,好比咱們點擊一個按鈕,去修改vuex中的數據

方式一 直接修改(不推薦)

<template>
  <div class="box">
      <h2>{{msg}}</h2>
      <el-button @click="changeVuex">修改</el-button>
  </div>
</template>

<script>
export default {
    methods: {
        // 直接賦值修改vuex中的state的數據
        changeVuex(){
            this.$store.state.msg = '修改vuex'
        },
    },
    computed: {
        msg(){ return this.$store.state.msg }
    }
}
</script>

這種方式勉強能用,不過vuex當開啓了嚴格模式的時候,就會報錯,開啓嚴格模式代碼以下:

export default new Vuex.Store({
    strict:true, // 開啓嚴格模式
    state:{
        msg:'我是vuex哦'
    },
    // 等...
})

報錯信息圖以下:

報錯信息含義
Error:[vuex] do not mutate vuex store state outside mutation handlers.

不要不經過mutation的操做就去修改vuex中store裏面的state狀態值

因此由此咱們就想到了vuex定義的那句話:並以相應的規則保證狀態以一種可預測的方式發生變化這裏的相應的規則就是指,想要修改vuex中的數據,就要按照vuex中操做數據的步驟流程規則來,嘿嘿,要否則就給你報錯。那麼vuex定義的修改state的規則是什麼呢?請看下圖

方式二 action-->mutation-->state

咱們先看一下官方給到的圖解

看完上圖之後,咱們能夠總結vuex的使用規則以下

  • 組件想要去更改vuex中的數據,可是組件本身只是口頭傳喚一下actions幹活,即:dispatch一下actions

    (組件說:嘿,actions,我要更改vuex中的數據了,你發個請求,從後端接口中拿到我要的數據去更改一下)

  • action獲得消息後,就會向後端發請求,獲取到後端返回的數據,action拿到後端返回的數據之後,就把數據commit提交給mutations,即:commit一下mutations

    (actions拿到數據之後,可是也比較懶,把數據交給倉庫管理員mutations,告知要更改對應數據之後,就撤了)

  • mutations至關於最終的倉庫管理員,由這個倉庫管理員去修改vuex倉庫中的數據,即:mutate一下state

    (mutations不辭辛苦,就去更改vuex中state的數據,更改完之後,就等待下一次的幹活,mutations修改數據的過程,會被倉庫的監控,也就是vue的開發工具devTool記錄下來)

  • 而vue數據是響應式的,倉庫數據一改變,對應使用倉庫數據的組件就會從新render渲染,因此頁面效果也就改變了
組件中若是不是異步發請求去更改數據,也能夠直接跳過actions,直接讓倉庫管理員mutations去修改數據,不過這種方式不是太多

代碼以下

// 組件
<template>
  <div class="box">
      <h2>{{msg}}</h2>
      <el-button @click="changeVuex">修改</el-button>
  </div>
</template>

<script>
export default {
    methods: {
        changeVuex(){
            this.$store.dispatch('actionsChange')
        },
    },
    computed: {
        msg(){ return this.$store.state.msg }
    }
}
</script>
// vuex
export default new Vuex.Store({
    strict:true,
    state:{
        msg:'我是vuex哦'
    },
    mutations:{
        // 這裏第一個形參state就是倉庫state,是能夠訪問到state裏的msg的值,即 能夠修改state
        // 第二個形參params是actions中傳過來的數據
        mutationsChange(state,params){
            console.log(state,params);
            state.msg = params
        }
    },
    actions:{
        // 這裏的形參store對象下面有commit方法
        // 能夠去告知對應的mutations中的函數執行
        actionsChange(store){
            console.log(store);
            setTimeout(() => {
                store.commit('mutationsChange', '規範修改vuex')
            }, 500);
        }
    }
})

效果圖以下

devtool記錄mutations的操做

補充getter加工

getter中咱們能夠定義一個函數,這個函數咱們用來修改state中的值的,函數接收一個參數state,這個state參數就是當前的state對象,經過這個參數能夠加工state中的數據,加工好return出去,以供組件中使用

// vuex
export default new Vuex.Store({
    strict:true,
    state:{
        msg:'我是vuex哦'
    },
    getters:{
        gettersChange(state){
            return state.msg + '---getter修改state中的數據'
        }
    },
})

組件中使用的時候,就直接使用getter中的數據便可,以下:
this.$store.getters.gettersChange
固然也能夠不用getter,就是在組件中取到vuex中的數據之後,咱們再進行加工。不過能在getter中加工的最好就在getter中加工,由於這樣寫代碼,比較優雅

輔助函數

函數函數的出現,就是爲了讓咱們能少寫幾行代碼,咱們以獲取vuex中state爲例,假設咱們在一個組件中須要獲取多個state中的值,這樣的話這個語句就要寫屢次,this.$store.state.msg一、this.$store.state.msg二、this.$store.state.msg3等。爲了簡化,vuex內部封裝了四個輔助函數,分別用來對應state,mutations,actions,getters的操做。
輔助函數,簡而言之,就是尤大佬封裝的語法糖

輔助函數通常搭配計算屬性和方法使用

mapState輔助函數

第一步,假設vuex倉庫中有三個數據,咱們須要在組件上使用這三個數據

// store.js
export default new Vuex.Store({
    state:{
            msg1:'輔助函數一',
            msg2:'輔助函數二',
            msg3:'輔助函數三',
          },
}

第二步,從vuex插件中引入輔助函數
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
第三步,在計算屬性中使用輔助函數mapstate取到state中的數據

// 方式一,數組形式
computed: {
        ...mapState(['msg1','msg2','msg3'])
},
    
// 方式二, 對象形式(vuex模塊化比較經常使用)
computed: {
    ...mapState({
        msg1: state=>state.msg1,
        msg2: state=>state.msg2,
        msg3: state=>state.msg3,
    })
},

第四步,在組件中直接就能夠在差值表達式中使用了

<template>
    <div>
        <h1>{{msg1}}</h1>
        <h2>{{msg2}}</h2>
        <h3>{{msg3}}</h3>
    </div>
</template>

第五步,頁面效果圖以下

mapGetters輔助函數

使用方法和mapState基本同樣

computed:{
  ...mapGetters(['msg']),
}

mapMutations輔助函數

好比,咱們在按鈕點擊事件的回調函數中去觸發mutations,對比一下,不用輔助函數和用輔助函數的語法書寫區別
vuex結構

mutations:{
    kkk(state,params){
        state.msg = params
    }
},

html結構

<template>
  <div>
    <h2>{{ msg }}</h2>
    <el-button @click="kkk('我是參數')">輔助函數mapActions</el-button>
  </div>
</template>

js代碼

<script>
import { mapState, mapMutations } from "vuex";
export default {
  computed: {
    ...mapState(["msg"]),
  },
  methods: {
    // 不使用輔助函數的寫法
    kkk(params) {
      this.$store.commit("kkk", params);
    },
      
    // 使用輔助函數的寫法
    ...mapMutations(["kkk"]),
  },
};
</script>

注意:使用輔助函數,貌似沒有地方傳參,實際是輔助函數幫咱們默默的傳遞過去了,這個參數須要寫在html結構中的點擊語句中,如上述代碼:<el-button @click="kkk('我是參數')">輔助函數mapActions</el-button>

mapActions輔助函數

mapActions的用法和mapMutations的用法基本上同樣,就換個單詞便可,在此不贅述
...mapActions(["sss"])
意思是:去觸發Actions中的sss函數

vuex的module模塊化

提起模塊化,思想仍是那句話,大而化小,便於管理。不少語言都有模塊化的應用,vuex也是同樣。試想,若是全部的狀態數據都寫在一塊兒,看着容易眼花繚亂,不便於管理。因此尤大老對於vuex的設計中,就作了模塊化module的處理

圖解步驟

在組件中使用vuex模塊化

獲取vuex模塊中的數據

這裏以獲取state中的數據爲例,獲取getters中的數據寫法基本同樣,不贅述

<template>
  <div>
    <h2>{{ msg }}</h2>
  </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: "CodeVue",
  computed: {
    // 正常方式
    msg(){
      return this.$store.state.vue.module// 找state裏的vue模塊下的module的值
    },
      
    // 使用輔助函數方式,這裏用對象的寫法
    ...mapState({
      msg:state=>state.vue.module// 找state裏的vue模塊下的module的值
    })
  }
};
</script>

打印store對象,就能夠看到對應的值

修改vuex模塊中的數據

這裏以觸發mutations爲例,actions寫法基本一致,不贅述

  • 不使用輔助函數

    <template>
    <div>
     <h2>{{ msg }}</h2>
     <el-button @click="moduleChange">模塊化修改值</el-button>
    </div>
    </template>
    
    <script>
    export default {
    name: "CodeVue",
    computed: {
     ...mapState({
       msg:state=>state.vue.module
     })
    },
    methods: {
     moduleChange(){
       // 注意,直接提交對應模塊的方法便可,commit會自動找到對應vuex下的方法
       this.$store.commit('moduleChange','我是參數')
     }
    },
    };
    </script>
  • 使用輔助函數

    <template>
    <div>
     <h2>{{ msg }}</h2>
     <!-- 咱們在點擊事件的語句中,把data中定義的參數帶過去,去提交mutations -->
     <el-button @click="moduleChange(canshu)">模塊化修改值</el-button>
    </div>
    </template>
    
    <script>
    import { mapState, mapMutations } from 'vuex'
    export default {
    name: "CodeVue",
    data() {
     return {
       canshu:'我是參數'
     }
    },
    computed: {
     ...mapState({
       msg:state=>state.vue.module
     })
    },
    methods: {
     ...mapMutations(['moduleChange'])
    },
    };
    </script>
注意,上述我使用vuex的模塊化module的時候,沒有加上命名空間 namespace,因此去提交對應模塊下的mutations的時候,能夠直接寫 this.$store.commit('moduleChange','我是參數')...mapMutations(['moduleChange'])這樣的話,vuex會去本身全部模塊下去找 moduleChange這個函數,而後去修改。這樣的話,略微浪費性能,由於,默認狀況下,vuex模塊內部的 action、mutation 和 getter 是掛載註冊在 全局命名空間的,這樣使得多個模塊可以對同一 mutation 或 action去操做,就不停的找,直到找到爲止。可是通常狀況下,咱們使用vuex模塊化的時候都會加上命名空間,作到獨立、複用。接下來咱們說一下,vuex模塊化的標準用法,即加上命名空間的用法

命名空間

  • 不加命名空間,全部的都找一遍。
  • 加了的話,只去特定的模塊找
  • 因此使用命名空間的話,提交mutations寫法就變了

寫法以下

// 不使用輔助函數
moduleChange(){
    this.$store.commit('vue/moduleChange'); // 以斜槓分割,斜槓前寫對應模塊名,斜槓後寫對應mutations中的方法名
}
    
// 使用輔助函數
...mapMutations('vue',['moduleChange']) // 以逗號分割,逗號前寫模塊名,逗號後是個數組,數組中放置對應mutations中的方法名

//3.別名狀態下
...mapMutations({
    anotherName:'vue/moduleChange' // 和不使用輔助函數同樣
}),

總結

讓咱們還回到vuex官網下定義的那句話:

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

貌似這樣定義還挺好的,科學嚴謹...

最後一首打油詩送給各位看官,娛樂一下,哈哈

《碼破蒼穹》碼宗強者名尤大代碼化翼走天下隨手祭出VUE恐怖如斯真可怕筆者碼渣雖技薄但卻心中有夢呀還望各位大佬們點贊鼓勵一下哈

相關文章
相關標籤/搜索