1. 程式人生 > >Vuex實踐(下)-mapState和mapGetters

Vuex實踐(下)-mapState和mapGetters

  Vuex系列文章

  《Vuex實踐(上)》

  《Vuex實踐(中)-多module中的state、mutations、actions和getters》

  《Vuex實踐(下)-mapState和mapGetters》

  

一.前言

  本文章是vuex系列的最後一篇,主要總結的是如何使用mapState和mapGetters訪問vuex中的state和getters。

二.多個模組中mapState和mapGetters的使用

  上一篇文章《Vuex實踐(中)》裡面我們總結的就是多模組的內容,所以關於store.js、moduleA.js和moduleB.js的程式碼保持不變。

  在此為了方便觀看,我將這三個檔案的程式碼在貼在這裡

E:\MyStudy\test\VueDemo\src\vuex\store.js

 1 import Vue from 'vue'
 2 import Vuex from 'vuex'
 3 import moduleA from './moduleA'
 4 import moduleB from './moduleB'
 5 
 6 Vue.use(Vuex)
 7 
 8 export default new Vuex.Store({
 9     state: {
10         counter: 1000
11     },
12     mutations: {
13         //遞增
14         increase(state) {
15             console.log("store-increase")
16             state.counter++
17         },
18         //遞減
19         decrement(state) {
20             state.counter--
21         }
22     },
23     actions: {
24         increaseAction(context) {
25             setTimeout(function(){
26                 //action通過提交mutation改變共享資料狀態
27                 context.commit('increase');
28             },3000)
29         },
30         decrementAction(context){
31             setTimeout(function(){
32                 //action通過提交mutation改變共享資料狀態
33                 context.commit('decrement');
34             },3000)
35         }
36     },
37     getters: {
38         doubleCounter(state) {
39             return state.counter*state.counter
40         }
41     },
42     modules: {
43         a: moduleA,
44         b: moduleB
45     }
46 })

 

E:\MyStudy\test\VueDemo\src\vuex\moduleA.js

const moduleA = {
    namespaced: true,
    state:{
        counter: 100
    },
    mutations: {
        //遞增
        increase(state) {
            console.log("moduleA-increase")
            state.counter++
        },
        //遞減
        decrement(state) {
            state.counter--
        }
    },
    actions: {
        increaseAction(context) {
            setTimeout(function(){
                //action通過提交mutation改變共享資料狀態
                context.commit('increase');
            },3000)
        },
        decrementAction(context){
            setTimeout(function(){
                //action通過提交mutation改變共享資料狀態
                context.commit('decrement');
            },3000)
        }
    },
    getters: {
        doubleCounter(state) {
            return state.counter*state.counter
        }
    }
}

export default moduleA

 

E:\MyStudy\test\VueDemo\src\vuex\moduleB.js

 1 const moduleB = {
 2     namespaced: true,
 3     state:{
 4         counter: 5
 5     },
 6     mutations: {
 7         //遞增
 8         increase(state) {
 9             console.log("moduleB-increase")
10             state.counter++
11         },
12         //遞減
13         decrementAction(state) {
14             state.counter--
15         }
16     },
17     actions: {
18         increaseAction(context) {
19             setTimeout(function(){
20                 //action通過提交mutation改變共享資料狀態
21                 context.commit('increase');
22             },3000)
23         },
24         decrementAction(context){
25             setTimeout(function(){
26                 //action通過提交mutation改變共享資料狀態
27                 context.commit('decrement');
28             },3000)
29         }
30     },
31     getters: {
32         doubleCounter(state){
33             return state.counter*state.counter
34         }
35     }
36 }
37 
38 export default moduleB

 

  現在需要在元件中使用mapState和mapGetters

  還是按照之前的套路

  在App.vue元件中訪問根根模組store和a模組moduleA的state和getters。

  在Index.vue元件中訪問b模組moduleB的state和getters

1.使用mapState

  使用mapState訪問state的寫法也有多種,我們一個一個來實踐(不包含es6的寫法)

  [第一種寫法]

E:\MyStudy\test\VueDemo\src\App.vue  

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 獲取共享資料 -->
    <h1>這裡是App元件</h1>
    <h3> App元件獲取共享資料 </h3>
    <h3>使用mapState訪問根元件counter : {{counter}}</h3>
    <h3>使用mapState訪問a元件counter : {{counterA}}</h3>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
import { mapState } from 'vuex'
export default {
  name: 'App',
  components: { Index },
  computed: mapState({
    //訪問store根模組
    counter: function(state){
      return state.counter
    },
    //訪問a模組
    counterA: function(state){
      return state.a.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>

 

E:\MyStudy\test\VueDemo\src\components\Index.vue

<template>
    <div>  
        <h1>這裡是Index.vue元件</h1>
        <h3>Index元件獲取共享資料 </h3>
        <h3>使用mapState訪問b模組counter :{{ counterB }}</h3>
    </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
    name: 'Index',
    computed: mapState({
        counterB: function(state){
            return state.b.counter
        }
    })
}
</script>

 

  在App.vue、Index.vue元件中使用mapState,首先第一步需要引入mapState。

  接著就是在計算屬性computed中使用,以Index.vue中的程式碼為例

computed: mapState({
    counterB: function(state){
         return state.b.counter
    }
})

     可以看到mapState關聯到vue的計算屬性中。

  獲取b模組的state,只需要以vue計算屬性的形式在函式中返回state.b.counter即可。

  (獲取根模組state返回state.counter;獲取a模組state返回state.a.counter)

  這樣在模板中就可以使用計算屬性的語法訪問state

  備註:這種方式,當註釋掉名稱空間的配置後,依然可以正常訪問到不同模組的state

  [第二種寫法]

  第二種寫法和第一種有些類似,只是以字串的形式返回計算屬性。

  我們先在Index.vue元件中訪問b模組的資料。

E:\MyStudy\test\VueDemo\src\components\Index.vue

 1 <template>
 2     <div>  
 3         <h1>這裡是Index.vue元件</h1>
 4         <h3>Index元件獲取共享資料 </h3>
 5         <h3>使用mapState訪問b模組counter :{{ counterB }}</h3>
 6     </div>
 7 </template>
 8 <script>
 9 import { mapState } from 'vuex'
10 export default {
11     name: 'Index',
12     computed: mapState('b',{
13         counterB: 'counter'
14     })
15 }
16 </script>

  核心程式碼如下

computed: mapState('b',{
    counterB: 'counter'
})

    可以看到,mapState第一個引數限定了模組名稱。

  接著就是以'counter'字串的形式返回了b模組的counter值。

  那麼根據之前一系列的總結,可知

    訪問根模組的資料,不需要限定第一個引數;

    訪問a模組的資料,需要限定第一個引數為a

  然而,因為訪問根模組和訪問a模組同在App.vue元件中,那麼因為mapState第一個引數限定的問題,我們需要編寫兩個mapState。

  現在直接上程式碼(只把computed中的核心程式碼貼上)

E:\MyStudy\test\VueDemo\src\App.vue  

computed: {
    ...mapState({
      //訪問store根模組
      counter: 'counter',
    }),
    ...mapState('a',{
      //訪問a模組
      counterA: 'counter'
    })
}

  可以看到,我寫了兩個mapState,還是...mapState的形式。

  ...mapState它是ES6中擴充套件運算子的語法,應用在mapState上,官方文件是這樣說的

  

   (

    此處若對此有疑問,可以在去仔細研究一下物件擴充套件運算子的內容。

    我這裡貼一個簡單的示例

    

      最終newObj的列印結果為  

    相信這個示例可以很清楚的解釋我們寫的兩個...mapState的寫法

  )

  官方文件處提到這個物件展開運算子的場景是為了將一個元件中原本的計算屬性和mapState混合使用

  (混合使用這個點日常開發會用到,很實用的一個點)。

  那本次我們也是使用這個語法成功的獲取到了不同模組的state。

 

  最後我們在使用瀏覽器檢視一下最終App.vue和Index.vue中的結果

  

  我們已經使用mapState成功的訪問到了多模組中的state資料。

 

  備註:這種關於mapState的寫法不能刪除moduleA和moduleB中關於命令空間的配置,否則會報錯。

  最後作者還嘗試了一個問題,就是將moduleA.js中的state屬性改為counterA

  

  然後修改了App.vue元件中computed訪問a模組資料的程式碼

  

  最後發現這樣並不能正常訪問到a模組的state資料。(刪除a模組的名稱空間配置也無法正常訪問)

  這個嘗試僅給大家一個反面的示例。

2.使用mapGetters

  前面使用mapState訪問了state資料,那麼現在我們使用mapGetters訪問一下vuex中的getters。

  在研究之後發現,暫時發現使用mapGetters訪問一下vuex中的getters只有字串的形式。

E:\MyStudy\test\VueDemo\src\App.vue

 1 <template>
 2   <div id="app">
 3     <img src="./assets/logo.png">
 4     <!-- 獲取共享資料 -->
 5     <h1>這裡是App元件</h1>
 6     <h3> App元件獲取共享資料 </h3>
 7     <h3>使用mapState訪問根元件counter : {{counter}}</h3>
 8     <h3>使用mapState訪問a元件counter : {{counterA}}</h3>
 9     <h3>使用mapGetters訪問根元件doubleCounter : {{doubleCounter}}</h3>
10     <h3>使用mapGetters訪問a元件doubleCounter : {{doubleCounterA}}</h3>
11     <hr/>
12     <Index></Index>
13   </div>
14 </template>
15 
16 <script>
17 import Index  from './components/Index'
18 import { mapState,mapGetters } from 'vuex'
19 export default {
20   name: 'App',
21   components: { Index },
22   computed: {
23     ...mapState({
24       //訪問store根模組
25       counter: 'counter',
26     }),
27     ...mapState('a',{
28       //訪問a模組
29       counterA: 'counter'
30     }),
31     ...mapGetters({
32       //訪問store根模組
33       doubleCounter: 'doubleCounter'
34     }),
35     ...mapGetters('a',{
36       //訪問store根模組
37       doubleCounterA: 'doubleCounter'
38     })
39 
40   }
41   
42 }
43 </script>
44 
45 <style>
46 #app {
47   font-family: 'Avenir', Helvetica, Arial, sans-serif;
48   -webkit-font-smoothing: antialiased;
49   -moz-osx-font-smoothing: grayscale;
50   text-align: center;
51   color: #2c3e50;
52   margin-top: 60px;
53 }
54 </style>

 

E:\MyStudy\test\VueDemo\src\components\Index.vue

 1 <template>
 2     <div>  
 3         <h1>這裡是Index.vue元件</h1>
 4         <h3>Index元件獲取共享資料 </h3>
 5         <h3>使用mapState訪問b模組counter :{{ counterB }}</h3>
 6         <h3>使用mapGetters訪問b元件doubleCounter : {{doubleCounterB}}</h3>
 7     </div>
 8 </template>
 9 <script>
10 import { mapState,mapGetters } from 'vuex'
11 export default {
12     name: 'Index',
13     computed: {
14         ...mapState('b',{
15             counterB: 'counter'
16          }),
17         ...mapGetters('b',{
18             doubleCounterB: 'doubleCounter'
19         }),
20     }
21 }
22 </script>

 

  瀏覽器檢視結果

  

三.總結

  到此本篇文章基本已經結束了,vuex系列的三篇文章也已經結束。

  關於vuex中大多數的用法基本已經覆蓋到,但是還有一些內容沒有覆蓋到。

  後期攢夠一篇在繼續更新

  在最後呢,再補充一點,不管是mapState和mapGetters,我們給傳入的都是一個字典。

  簡單一些的,假如我們的state和getters不重名,我們可以給mapState和mapGetters傳入一個數組

1 mapState([
2      'counterA','counterB',...
3 ])
4 
5 mapGetters([
6      'dobuleCounterA','dobuleCounterB',...
7 ])

  這樣陣列中的字串元素會直接去對映對應的state和getters。

  (字典形式相當於是將state和getters中的名稱在對映過程中進行重新命名)