Vuex實踐(上)


作者:小土豆

博客園:www.cnblogs.com/HouJiao/

掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d

微信公眾號:不知名寶藏程序媛(關注"不知名寶藏程序媛"免費領取前端電子書籍。文章公眾號首發,關注公眾號第一時間獲取最新文章。)

碼字不易,點贊鼓勵喲~

 

 一.前言

  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); } } })

 

  這里我們有幾點需要總結:

  1.異步修改數據定義在actions中,並且通過提交mutations改變共享數據的狀態

  2.在組件中需要使用$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中常用的內容

 

作者:小土豆

博客園:www.cnblogs.com/HouJiao/

掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d

微信公眾號:不知名寶藏程序媛(關注"不知名寶藏程序媛"免費領取前端電子書籍。文章公眾號首發,關注公眾號第一時間獲取最新文章。)

碼字不易,點贊鼓勵喲~

 


 

聲明:轉載請說明出處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM