震驚!喝個茶的時間就學會了vuex

weixin_34148340發表於2018-02-01

寫在前面

我很欣賞震驚部,因為他們的標題每次寫的都很好0.0

什麼是vuex

先給出官網地址

官方解釋: Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化
大白話:對資料(data)統一的管理,如果涉及到了資料的處理,來,到vuex裡面進出吧!就像是超市對商品的統一管理一樣

為了使用vuex而做的準備

安裝vuex

npm install --save vuex
<!--這裡假定你已經搭好vue的開發環境了--> 
複製程式碼

配置vuex

1、首先建立一個js檔案,假定這裡取名為store.js
2、在main.js檔案中引入上面建立的store.js

//main.js內部對store.js的配置
import store from '"@/store/store.js' 
//具體地址具體路徑
new Vue({
    el: '#app',
    store, //將store暴露出來
    template: '<App></App>',
    components: { App }
});
複製程式碼

store.js中的配置

import Vue from 'vue'; //首先引入vue
import Vuex from 'vuex'; //引入vuex
Vue.use(Vuex) 

export default new Vuex.Store({
    state: { 
        // state 類似 data
        //這裡面寫入資料
    },
    getters:{ 
        // getters 類似 computed 
        // 在這裡面寫個方法
    },
    mutations:{ 
        // mutations 類似methods
        // 寫方法對資料做出更改(同步操作)
    },
    actions:{
        // actions 類似methods
        // 寫方法對資料做出更改(非同步操作)
    }
})

//可能有的地方書寫的風格不是這樣的,如果需要的瞭解的可以百度看看其他人的
複製程式碼

好了,基本的配置到這裡就結束了,接下來我們可以開始使用它們了;
下面結合一個購物車示例,我們來全面瞭解一下vuex的使用

開始使用vuex

我們約定store中的資料是以下形式

state:{
    goods: {
        totalPrice: 0,
        totalNum:0,
        goodsData: [
            {
                id: '1',
                title: '好吃的蘋果',
                price: 8.00,
                image: 'https://www.shangdian.com/static/pingguo.jpg',
                num: 0
            },
            {
                id: '2',
                title: '美味的香蕉',
                price: 5.00,
                image: 'https://www.shangdian.com/static/xiangjiao.jpg',
                num: 0
            }
        ]
    }
},
getters:{ //其實這裡寫上這個主要是為了讓大家明白他是怎麼用的,
    totalNum(state){
        let aTotalNum = 0;
        state.goods.goodsData.forEach((value,index) => {
            aTotalNum += value.num;
        })
        return aTotalNum;
     },
     totalPrice(state){
        let aTotalPrice = 0;
        state.goods.goodsData.forEach( (value,index) => {
            aTotalPrice += value.num * value.price
         })
         return aTotalPrice.toFixed(2);
    }
},
mutations:{
    reselt(state,msg){
        console.log(msg) //我執行了一次;
        state.goods.totalPrice = this.getters.totalPrice;
        state.goods.totalNum = this.getters.totalNum;
    },
    reduceGoods(state,index){ 
        //第一個引數為預設引數,即上面的state,後面的引數為頁面操作傳過來的引數
        state.goods.goodsData[index].num-=1;
        
        let msg = '我執行了一次'
        this.commit('reselt',msg);
    },
    addGoods(state,index){
        state.goods.goodsData[index].num+=1;
        
        let msg = '我執行了一次'
        this.commit('reselt',msg);
        /**
            想要重新渲染store中的方法,一律使用commit 方法 
            你可以這樣寫 commit('reselt',{
                state: state
            })
            也可以這樣寫 commit({
                type: 'reselt',
                state: state 
            })
            主要看你自己的風格
        **/
    }
},
actions:{
    //這裡主要是操作非同步操作的,使用起來幾乎和mutations方法一模一樣
    //除了一個是同步操作,一個是非同步操作,這裡就不多介紹了,
    //有興趣的可以自己去試一試
    //比如你可以用setTimeout去嘗試一下
}
複製程式碼

好了,簡單的資料我們就這樣配置了,接下來看看購物車頁面吧;

第一種方式使用store.js中的資料(直接使用)

<template>
    <div id="goods" class="goods-box">
        <ul class="goods-body">
            <li v-for="(list,index) in goods.goodsData" :key="list.id">
                <div class="goods-main">
                    <img :src="list.image">
                </div>
                <div class="goods-info">
                    <h3 class="goods-title">{{ list.title }}</h3>
                    <p class="goods-price">¥ {{ list.price }}</p>
                    <div class="goods-compute">
                        <!--在dom中使用方法為:$store.commit()加上store.js中的屬性的名稱,示例如下-->
                        <span class="goods-reduce" @click="$store.commit('reduceGoods',index)">-</span>
                        <input readonly v-model="list.num" />
                        <span class="goods-add" @click="$store.commit('addGoods',index)">+</span>
                    </div>
                </div>
            </li>
        </ul>
        <div class="goods-footer">
            <div class="goods-total">
                合計:¥ {{ goods.totalPrice }}
                <!--
                    如果你想要直接使用一些資料,但是在computed中沒有給出來怎麼辦?
                    可以寫成這樣
                    {{ $store.state.goods.totalPrice }}
                    或者直接獲取gettles裡面的資料
                    {{ $store.gettles.totalPrice }}
                -->
            </div>
            <button class="goods-check" :class="{activeChecke: goods.totalNum <= 0}">去結賬({{ goods.totalNum }})</button>
        </div>
    </div>
</template>
<script>
    export default {
        name: 'Goods',
        computed:{
            goods(){
                return this.$store.state.goods;
            }
        }
    }
</script>
複製程式碼

如果上面的方式寫引數讓你看的很彆扭,我們繼續看第二種方式

第一種方式使用store.js中的資料(通過輔助函式使用)

<!--goods.vue 購物車頁面-->
<template>
    <div id="goods" class="goods-box">
        <ul class="goods-body">
            <li v-for="(list,index) in goods.goodsData" :key="list.id">
                <div class="goods-main">
                    <img :src="list.image">
                </div>
                <div class="goods-info">
                    <h3 class="goods-title">{{ list.title }}</h3>
                    <p class="goods-price">¥ {{ list.price }}</p>
                    <div class="goods-compute">
                        <span class="goods-reduce" @click="goodsReduce(index)">-</span>
                        <input readonly v-model="list.num" />
                        <span class="goods-add" @click="goodsAdd(index)">+</span>
                    </div>
                </div>
            </li>
        </ul>
        <div class="goods-footer">
            <div class="goods-total">
                合計:¥ {{ goods.totalPrice }}
                <!--
                    getters裡面的資料可以直接這樣寫
                    {{ totalPrice }}
                -->
            </div>
            <button class="goods-check" :class="{activeChecke: goods.totalNum <= 0}">去結賬({{ goods.totalNum }})</button>
        </div>
    </div>
</template>
<script>
    import {mapState,mapGetters,mapMutations} from 'vuex';
    /**
        上面大括弧裡面的三個引數,便是一一對應著store.js中的state,getters,mutations
        這三個引數必須規定這樣寫,寫成其他的單詞無效,切記
        畢竟是這三個屬性的的輔助函式
    **/
    
    export default {
        name: 'Goods',
        computed:{
            ...mapState(['goods']) 
            ...mapGetters(['totalPrice','totalNum'])
            /**
                ‘...’ 為ES6中的擴充套件運算子,不清楚的可以百度查一下
                如果使用的名稱和store.js中的一樣,直接寫成上面陣列的形式就行,
                如果你想改變一下名字,寫法如下
                ...mapState({
                    goodsData: state => state.goods
                })
                
            **/
        },
        methods:{
            ...mapMutations(['reduceGoods','addGoods']),
            /**
                這裡你可以直接理解為如下形式,相當於直接呼叫了store.js中的方法
                reduceGoods(index){
                    // 這樣是不是覺得很熟悉了?
                },
                addGoods(index){
                    
                }
                好,還是不熟悉,我們換下面這種寫法
                
                onReduce(index){ 
                    //我們在methods中定義了onReduce方法,相應的Dom中的click事件名要改成onReduce
                    this.reduceGoods(index)
                    //這相當於呼叫了store.js的方法,這樣是不是覺得滿意了
                }
                
            **/
        }
    }
</script>
複製程式碼

最後來看看Module

在專案比較複雜的時候,資料全部寫在一個state 方法全部集中一個mutations中,將會使我們的檔案顯得太過於臃腫,而且不易維護,那怎麼辦呢?
還是那句話辦法總比問題多,vuex為我們提供了module這樣一個模組的概念。
我們可以利用它來根據我們個個元件或者頁面所需要的資料一一分割成不同的模組,看下面示例

const moduleA = {
  state: { /*data**/ },
  mutations: { /**方法**/ },
  actions: { /**方法**/ },
  getters: { /**方法**/ }
}

const moduleB = {
  state: { /*data**/ },
  mutations: { /**方法**/ },
  actions: { /**方法**/ }
  getters: { /**方法**/ }
}

export default new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

//那怎麼呼叫呢?看下面!

//在模組內部使用
state.goods //這種使用方式和單個使用方式樣,直接使用就行

//在元件中使用
store.state.a.goods //先找到模組的名字,再去呼叫屬性
store.state.b.goods //先找到模組的名字,再去呼叫屬性
複製程式碼

看看效果圖吧

寫在最後

謝謝大家的閱讀,如果本文讓你能有所收穫,深表榮幸,如果喜歡的,點個贊行 0.0

最後打一波廣告:歡迎大家關注我的微信公眾號:大前端js,當然為了回饋大家關注,裡面我放了一些學習資源,熱烈歡迎大家關注交流前端方面但不侷限前端方面的知識;

之前發出來的有很多單詞出錯的地方,對這樣的錯誤,深表歉意,也非常感謝大家的指正

原創不易,非商業轉載時請註明出處與原文連結,商業轉載請得到本人允許,謝謝!

文章講解的小例子已經放到GitHub上面去了,github專案地址,喜歡的話就給個Star吧 0.0

相關文章