1. 程式人生 > >Vuex入門實踐(上)

Vuex入門實踐(上)

 

 

 一.前言

  vuex被稱為是專為vue應用程式開發的的狀態管理模式。它的作用使用一句話描述就是:讓元件之間可以共享資料

  話不多少,先拋開概念,我們寫一個簡單的示例感受一波。

二.專案開發環境

  專案開發環境搭建請移步作者的另外一篇文章《使用vue-cli搭建專案開發環境》

  本次的專案目錄如下:

  

三.安裝vuex

  使用vuex前需要先進行安裝,安裝命令:npm install vuex --save--dev

  

四.建立和訪問共享資料

1.使用vuex建立全域性共享資料

  我們先需要在E:\MyStudy\test\VueDemo\src\目錄下新建一個目錄vuex和檔案store.js

  

   現在在store中使用vuex建立一個全域性的共享資料

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

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中建立一個全域性共享的資料 counter
    state: {
        counter: 0
    }
})

  可以看到使用vuex建立一個共享資料的語法也比較簡單,即在new Vuex.Store中定義state物件,在state物件中就可以建立全域性的共享物件,本次我們建立了一個counter資料。

2.入口檔案中配置vuex

  共享資料前面我們已經建立好了,接著需要在入口檔案main.js中配置vuex

    1.引入我們編寫的關於vuex的程式碼模組store.js

    2.在根例項上配置vuex

E:\MyStudy\test\VueDemo\src\main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router/router'
//1.引入vuex
import store from './vuex/store'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>',
  router: router,
  // 2.根例項上配置vuex
  store: store
})

 

3.元件中獲取共享資料

  前面我們已經完成了兩件事:使用vuex建立了共享資料counter和配置了vuex。

  接著我們就需要在元件中訪問這個共享資料counter

  我們先新建一個Index.vue元件,在該元件中編寫訪問counter的程式碼

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

 1 <template>
 2     <div>  
 3         <h1>這裡是Index.vue元件</h1>
 4         <h1>Index元件獲取共享資料:{{ $store.state.counter }}</h1>
 5     </div>
 6 </template>
 7 <script>
 8 export default {
 9     name: 'Index'
10 }
11 </script>

 

  訪問共享資料counter的程式碼為:

<h1>Index元件獲取共享資料:{{ $store.state.counter }}</h1>

  接著在App.vue中編寫同樣的程式碼訪問這個counter,並且在App.vue元件中將Index.vue元件引入並展示。

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     <h1> App元件獲取共享資料 : {{ $store.state.counter }} </h1>
 7     <hr/>
 8     <Index></Index>
 9   </div>
10 </template>
11 
12 <script>
13 import Index  from './components/Index'
14 export default {
15   name: 'App',
16   components: { Index }
17 }
18 </script>
19 
20 <style>
21 #app {
22   font-family: 'Avenir', Helvetica, Arial, sans-serif;
23   -webkit-font-smoothing: antialiased;
24   -moz-osx-font-smoothing: grayscale;
25   text-align: center;
26   color: #2c3e50;
27   margin-top: 60px;
28 }
29 </style>

 

4.瀏覽器檢視結果

  我們分別在App.vue元件和Index.vue元件中訪問了共享資料counter,現在我們啟動專案在瀏覽器中看下結果。

  

  可以看到,App元件和Index元件均可以訪問到counter的值。

  

  到此,我們簡單的建立一個共享資料並且在元件中成功的訪問到了這個共享資料,這裡我們做一個小總結

    1.安裝vuex:npm install vuex

    2.全域性配置vuex:建立vuex例項,呼叫store方法配置在state中建立共享資料。

    3.元件中使用$store.state.counter可以訪問到共享資料

五.修改共享資料

1.在store定義共享資料的修改狀態

  vuex中,假如需要改變共享資料,必須在vuex例項物件的Store方法中約定這個變化。

  我們在store.js中對counter做兩個約束:遞增和遞減。

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

 1 import Vue from 'vue'
 2 import Vuex from 'vuex'
 3 
 4 Vue.use(Vuex)
 5 
 6 export default new Vuex.Store({
 7     // 在state中建立一個全域性共享的資料 counter
 8     state: {
 9         counter: 0
10     },
11     mutations: {
12         // 遞增
13         increase(state) {
14             state.counter++ 
15         },
16         // 遞減
17         decrement(state) {
18             state.counter--
19         }
20     }
21 })

 

  其中13行的increase方法就是約定共享資料counter每次遞增1;

  17行的decrement方法約定共享資料counter每次遞減1。  

2.元件中觸發counter遞增和遞減

  我們在App.vue元件中觸發counter遞減,在Index.vue中觸發counter遞增

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     <h1> App元件獲取共享資料 : {{ $store.state.counter }} </h1>
 7     <button v-on:click="$store.commit('decrement')">點選觸發共享資料counter遞減1</button>
 8     <hr/>
 9     <Index></Index>
10   </div>
11 </template>
12 
13 <script>
14 import Index  from './components/Index'
15 export default {
16   name: 'App',
17   components: { Index }
18 }
19 </script>
20 
21 <style>
22 #app {
23   font-family: 'Avenir', Helvetica, Arial, sans-serif;
24   -webkit-font-smoothing: antialiased;
25   -moz-osx-font-smoothing: grayscale;
26   text-align: center;
27   color: #2c3e50;
28   margin-top: 60px;
29 }
30 </style>

 

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

<template>
    <div>  
        <h1>這裡是Index.vue元件</h1>
        <h1>Index元件獲取共享資料:{{ $store.state.counter }}</h1>
        <button v-on:click="$store.commit('increase')">點選該元件觸發共享資料counter遞增1</button>
    </div>
</template>
<script>
export default {
    name: 'Index'
}
</script>

 

  可以看到在元件中觸發共享資料counter遞增和遞減的邏輯分別為:$store.commit('increase') 和 $store.commit('decrement'),即使用$store.commit方法並傳遞對應的函式名稱。

3.瀏覽器檢視結果

  

   可以看到,點選App元件中的按鈕,成功的將counter加1,且Index元件中的資料也自動更新;

  點選Index元件中的按鈕,成功的將counter加1,App元件中的資料也自動更新

 

六.非同步修改共享資料

  假設我們上面的遞增遞減的需求變成:點選按鈕後,過3秒再去修改counter的值。那麼這個時候應該怎麼實現呢?我們直接上程式碼。

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

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中建立一個全域性共享的資料 counter
    state: {
        counter: 0
    },
    mutations: {
        // 遞增
        increase(state) {
           state.counter++    
        },
        // 遞減
        decrement(state) {
           state.counter--   
        }
    },
    actions: {
        increaseAction(context){
            setTimeout(function(){
                context.commit('increase')
            }, 3000); 
        },
        decrementAction(context){
            setTimeout(function(){
                context.commit('decrement')
            }, 3000); 
        }
    }
})

 

  可以看到,我們的非同步修改資料定義在actions中,在元件中需要使用$store.dispatch去觸發。

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     <h1> App元件獲取共享資料 : {{ $store.state.counter }} </h1>
 7     <button v-on:click="$store.dispatch('decrement')">點選等待3秒觸發共享資料counter遞減1</button>
 8     <hr/>
 9     <Index></Index>
10   </div>
11 </template>
12 
13 <script>
14 import Index  from './components/Index'
15 export default {
16   name: 'App',
17   components: { Index }
18 }
19 </script>
20 
21 <style>
22 #app {
23   font-family: 'Avenir', Helvetica, Arial, sans-serif;
24   -webkit-font-smoothing: antialiased;
25   -moz-osx-font-smoothing: grayscale;
26   text-align: center;
27   color: #2c3e50;
28   margin-top: 60px;
29 }
30 </style>

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

<template>
    <div>  
        <h1>這裡是Index.vue元件</h1>
        <h1>Index元件獲取共享資料:{{ $store.state.counter }}</h1>
              <button v-on:click="$store.dispatch('increase')">點選等待3秒觸發共享資料counter遞增1</button>
    </div>
</template>
<script>
export default {
    name: 'Index'
}
</script>

  瀏覽器檢視結果:

  

  可以看到,setTimeout這個非同步邏輯成功執行。

  看這裡!!!   

  關於上面想要實現的非同步遞增和遞減,我們的第一反應可能就是在mutations中的遞增遞減函式添setTimeout延遲執行函式,我們來實踐一下。

  App.vue和Index.vue不做任何修改,還是前面的內容,只修改store.js。

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

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中建立一個全域性共享的資料 counter
    state: {
        counter: 0
    },
    mutations: {
        // 遞增
        increase(state) {
            // 新增定時器執行
            setTimeout(function(){
                state.counter++
            },3000);
             
        },
        // 遞減
        decrement(state) {
            //新增定時器
            setTimeout(function(){
                state.counter--
            },3000);
            
        }
    }
})

 

  瀏覽器看下結果:

  

  

  可以看到效果和actions一樣!!!

 

  沒辦法,我這人就是想多造作造作,對於mutations官網確實有明確的說明,mutations必須是同步函式。

 

  

  emmmmm,先拋開官方文件的說法,我們的示例跑出來的結果確實是說明了mutations可以是非同步函式。

  那麼如何解釋官方文件的說法呢?我還是一遍一遍的看了下文件,找到了一些重要的資訊:

  

  當我仔細讀了紅色框裡面的內容後,我大概理解了官方文件的為什麼說mutation必須是同步函數了。

  原因一:如果是非同步函式,在觸發mutation的時候,瀏覽器的除錯功能看不到資料的變化;

  原因二:mutation中非同步函式中的資料變化無法追蹤。

  到這裡呢,我們就不繼續往下探究了,因為基礎的還沒有總結完,基礎總結完後在探究這個問題。

 七.共享資料的計算屬性

vue元件中的計算屬性想必大家都知道,那麼vuex中共享資料的計算屬性的用途和原理也是同vue元件中的計算屬性。

我們假設vue元件中需要對共享資料做一些其他的轉換:將某個字串進行翻轉,並且轉為大寫。(這個場景專案中幾乎不會用到,僅僅為了演示而編造的。)

$store.state.split("").reverse().join("").toUpperCase();

當多個元件都需要這樣的轉化時,想必寫起來也會比較繁瑣,因此vuex共享資料的計算屬性就幫了我們解決這個問題。下面我們使用vuex的共享資料的計算屬性來實現這個需求

E:\MyStudy\test\VueDemo\src\vuex\store.js  在該檔案中已經將前面定義的counter刪除,重新定義了一個共享資料str

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中建立一個全域性共享的資料 str
    state: {
        str: 'hello'
    },
    getters: {
        reverseAndToUpper(state){
            return state.str.split("").reverse().join("");
        }
    }
})

 

  關於共享資料的計算屬性的訪問,我們只在App元件中新增訪問程式碼

E:\MyStudy\test\VueDemo\src\App.vue 在App元件中,將Index元件的引入程式碼已經刪除

 1 <template>
 2   <div id="app">
 3     <img src="./assets/logo.png">
 4     <!-- 獲取共享資料 -->
 5     <h1>這裡是App元件</h1>
 6     <h1> App元件獲取共享資料 : {{ $store.getters.reverseAndToUpper }} </h1>
 7   </div>
 8 </template>
 9 
10 <script>
11 import Index  from './components/Index'
12 export default {
13   name: 'App',
14   components: { Index }
15 }
16 </script>
17 
18 <style>
19 #app {
20   font-family: 'Avenir', Helvetica, Arial, sans-serif;
21   -webkit-font-smoothing: antialiased;
22   -moz-osx-font-smoothing: grayscale;
23   text-align: center;
24   color: #2c3e50;
25   margin-top: 60px;
26 }
27 </style>

 

  瀏覽器檢視一下結果:

  

  可以看到,已經成功的訪問到了str的計算屬性。

八.總結

  前面我們一共實踐了vuex的這些內容:

    1.在state中定義共享屬性,在元件中可使用[$store.state.屬性名]訪問共享屬性

    2.在mutations可中定義修改共享資料的方法,在元件中可使用[$store.commit('方法名')]同步修改共享屬性

    3.在actions中可定義非同步修改共享資料的方法,在元件中可使用[$store.dispatch('方法名')]非同步修改共享屬性

    4.在getters中可定義共享資料的計算屬性,在元件中可使用[$store.getters.計算屬性名]訪問共享資料的計算屬性

  後面會繼續更新vuex中常用的內容

 


 

宣告:轉載請說明出處

&n