直白話講述vue-cli工程中vuex 的使用

參考官方文檔
https://vuex.vuejs.org/zh-cn/

Vuex 是什麼?

官方是這麼解釋的:

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,
並以相應的規則保證狀態以一種可預測的方式發生變化。
Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、
狀態快照導入導出等高級調試功能。

讀完了,你發現,這說的啥啊?完全沒有看懂啊?
好吧!那就簡單總結一句話,vuex就是處理vue中組件之間通信的
有了這個,你再也不用煩惱vue跨組件通信了。
因爲Vuex裏的數據都是響應式的,任何組件使用同一store的數據,
只要store的數據變化,與之對應的組件都會立即變化

安裝

npm安裝

npm install vuex --save

CDN
https://unpkg.com/vuex
這種方式引入的話,要放在vue.js後邊
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
裝好後怎麼使用它?
首先在src目錄下建立一個store文件,再這個文件夾下新建一個index.js,打開index.js

寫入代碼:

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

Vue.use(Vuex)

export default new Vuex.Store({

})
或者
const store =  new Vuex.Store({

})
export default store

在main.js引入這個文件

// index.js創建完畢然後打開main.js
import Vue from 'vue'

import App from './App'

// 引入store文件下的index.js,如果你是index.js文件
// 引入的時候可以省略index.js,若是其它文件名.js請全部引入
// 比如:import store from './store/store.js'
import store from './store'


new Vue({
  el: '#app',
  store, // 然後再這裏使用一下
  components: { App },
  template: '<App/>'
})

下邊介紹核心概念就4個

State  
Getter
Mutation
Action
廢話不多說,啥意思看官方解釋,這裏只說怎麼用

State

state幹啥的,官方解釋一大堆,看完了我也覺得懵逼,這是啥啊?
其實state簡單理解就是存儲數據的,相當於我們的.vue文件裏的data裏造數據差不多

打開store文件下的index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state:{
    //這裏我們創建個數組
    foodlist:[
      {name:'大米',price:20,count:5},
      {name:'雞腿',price:10,count:8},
      {name:'沙拉',price:5,count:10},
      {name:'土豆',price:13,count:2}
    ]
  }
})

準備兩個組件(名字你隨意啊)
Header.vue

// 在Header.vue中拿到存在state裏的數據然後渲染在頁面中
// 1.直接使用$store.state.foodlist獲取state裏的數據(你在state裏定義的是什麼名字就用什麼名字)
<template>
    <div class="header">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in list" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>  
    </div>
</template>

<script>
export default {
    data(){
        return{
            list:this.$store.state.foodlist
        }
    }
};
</script>

<style scoped>
span{
    margin-left: 40px;
}
.header {
  width: 600px;
  height: 200px;
  margin-left: 50px;
  border: 1px solid #000;
  background-color: antiquewhite;
}
</style>

Foot.vue

<template>
    <div class="foot">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in list" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>  
    </div>
</template>

<script>
export default {
    data(){
        return{
            list:this.$store.state.foodlist
        }
    }
};
</script>

<style scoped>
span{
    margin-left: 40px;
}
.foot {
  width: 600px;
  height: 200px;
  margin-left: 50px;
  background-color: azure;
  border: 1px solid #000;
  margin-top: 50px;
}
</style>
使用了$store
兩個組件的數據是不是一毛一樣!這時候不同的組件就都拿到了數據
後邊的3個方法就只用一個組件測試了!其它組件用法都一樣的

改寫header.vue

// 上邊這種方法雖然也可以拿到數據,但官方推薦使用計算屬性的方式獲取數據
<template>
    <div class="foot">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in getList" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>  
    </div>
</template>

<script>
export default {
    computed:{
        // 定義一個方法,return 你的數據
        getList(){
            return this.$store.state.foodlist;
        }
    }
};
</script>

Mutation

這裏不先說getter,因爲很好明白,state存數據,那getter看名字就知道是取數據,因爲已經有$store.state可以
取到數據了,我們等會說getter,這裏我們說改變數據,在組件內,來自store的數據只能讀取,那我們肯定想怎麼改
state裏的數據,而修改store裏的數據的唯一途徑就是顯示的提交mutation,啥意思啊!看不懂最後一句,沒有關係,
我們知道你有改數據的需求的地方,只會在某一個組件內,而你不可能手動去store裏改,因爲state裏的數據都是接口
請求下來的,那麼怎麼改呢,我們需要用$store.commit(),官方解釋的這個方法是在組件內向store裏顯示提交mutation

說白了,就是在你的mutation裏先定義好了一個操作state裏的數據的方法,然後在你的組件裏調一下你定義
-----------------------------------------------------

在mutation裏那個的方法名,不過需要注意的是mutation裏的方法不推薦進行異步操作,這個我們等會說
-----------------------------------

打開store的js文件

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

Vue.use(Vuex)

export default new Vuex.Store({
  state:{
    //這裏我們創建個數組
    foodlist:[
      {name:'大米',price:20,count:5},
      {name:'雞腿',price:10,count:8},
      {name:'沙拉',price:5,count:10},
      {name:'土豆',price:13,count:2}
    ]
  },
  mutations:{
    // 定義一個增加價格的方法
    addPrice(state){
        // 先遍歷數組,獲取到價格屬性
        state.foodlist.forEach(e => {
          //這裏得到每一個對象
            //console.log(e) 
            e.price +=5; //每次點擊+5
        });
    }
  }
})

Header.vue文件中調用

// 準備一個點擊事件(樣式代碼就不貼了)
<template>
    <div class="foot">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in getList" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>
        //按鈕點擊事件
        <button @click="add">點擊加5</button>  
    </div>
</template>

<script>
export default {
    computed:{
        getList(){
            return this.$store.state.foodlist;
        }
    },
    methods:{
        add(){
            // 這裏調用你定義的增加價格的方法
            this.$store.commit('addPrice')
        }
    }
};
</script>

有裝vue-devtools插件的看的很清楚貼個圖
這裏寫圖片描述

// 這裏也是接受傳參的,修改代碼傳個參數5
<script>
export default {
    computed:{
        getList(){
            return this.$store.state.foodlist;
        }
    },
    methods:{
        add(){
            this.$store.commit('addPrice',5)
        }
    }
};
</script>

store裏的js

// mutation 默認接收的第一個參數就是state
mutations:{
  // 定義一個增加價格的方法
  addPrice(state,num){
      // 先遍歷數組,獲取到價格屬性
      state.foodlist.forEach(e => {
        //這裏得到每一個對象
          //console.log(e) 
          e.price +=num; //每次點擊+5
      });
  }
}

這裏寫圖片描述


mutation 異步操作出現的問題

上邊說過,mutation裏的方法不推薦進行異步操作,那會出現什麼問題,
這裏我們用延時模擬個異步,我們點擊按鈕進行+5的操作,2秒後讓頁面數據改變

打開store下的js文件

// 模擬延時2秒
  mutations:{
    // 定義一個增加價格的方法
    addPrice(state,num){
        // 先遍歷數組,獲取到價格屬性
        state.foodlist.forEach(e => {
            setTimeout(function(){
              e.price +=num;
            },2000) //延時2秒
        });
    }
  }
這時候你在頁面中點擊按鈕一次,過了兩秒,數據改變了,當你連點時,你會發現你都不點了,數據還在頁面中慢慢變化,
這顯然不是我們想要的,這時候你打開控制檯,你會看到方法都執行了,數據還沒有變化,知道運行到最後一次執行的時
候,數據才變化完,這個時候我們就要用另一個屬性了action

這裏寫圖片描述


Action

action和muation很像,只不過不同的是action裏提交的mutation,啥意思?
就是在action屬性裏調用的是mutation裏的方法,而且只能對mutation進行操作

打開store下的js文件

// 添加action屬性

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

Vue.use(Vuex)

export default new Vuex.Store({
  state:{
    //這裏我們創建個數組
    foodlist:[
      {name:'大米',price:20,count:5},
      {name:'雞腿',price:10,count:8},
      {name:'沙拉',price:5,count:10},
      {name:'土豆',price:13,count:2}
    ]
  },
  mutations:{
    // 定義一個增加價格的方法
    addPrice(state,num){
        // 先遍歷數組,獲取到價格屬性
        state.foodlist.forEach(e => {
          //這裏得到每一個對象
            //console.log(e) 
            e.price +=num; //每次點擊+5
        });
    }
  },
  actions:{
      Moniyibu(context){
        console.log(context)
        setTimeout(function(){
          context.commit('addPrice',5)
        },2000)
      }
  }
})

header.vue中

// 在組件內觸發 action 裏的方法,只能通過$store.dispatch 來觸發
<template>
    <div class="foot">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in getfood" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>
        <button @click="add">+</button>  
    </div>
</template>

<script>
export default {
    computed:{
        getList(){
            return this.$store.state.foodlist;
        },
        getfood(){
            return this.$store.getters.getfoodName
        }
    },
    methods:{
        add(){
        // 觸發action的方法Moniyibu
          this.$store.dispatch('Moniyibu',5)
        }
    }
};
這時候你再查看那個控制檯,你會發現,點擊按鈕,2秒鐘後方法才執行

Getter

該說的都說了,最後來說下getter,上邊說了,getter也是獲取數據的,但它裏邊的數據通常都是處理過的數據
比如有這樣一個需求,我們獲取state裏食物價格大於10的數據

打開store下的js文件

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

Vue.use(Vuex)

export default new Vuex.Store({
  state:{
    //這裏我們創建個數組
    foodlist:[
      {name:'大米',price:20,count:5},
      {name:'雞腿',price:10,count:8},
      {name:'沙拉',price:5,count:10},
      {name:'土豆',price:13,count:2}
    ]
  },
  // getters 使用
  getters:{
      // 獲取價格大於10的數據
      getfoodName:state =>{

        /**
         * filter 過濾,會根據你的判端條件進行篩選,把滿足條件的數據返回組成一個新的數組,
         * 這裏要把這個數組再return 回去,你也可以定一個變量接收這個新數組,然後return這個變量
         */
        return  state.foodlist.filter(foodname =>{
            //獲取每一條對象
            console.log(foodname) 
            // 返回每條數據價格大於10的數據
            return foodname.price > 10
        })
      }
  },
  mutations:{
    // 定義一個增加價格的方法
    addPrice(state,num){
        // 先遍歷數組,獲取到價格屬性
        state.foodlist.forEach(e => {
          //這裏得到每一個對象
            //console.log(e) 
            e.price +=num; //每次點擊+5
        });
    }
  }
})

Header.vue中獲取getter裏的數據

// 依舊寫在計算屬性裏 使用 $store.getters.getter裏的方法名
<template>
    <div class="foot">
        <span>食物</span>
        <span>價格</span>
        <span>數量</span>
        <ul>
            <li v-for="(food,index) in getfood" :key="index">
               {{food.name}}———{{food.price}}————{{food.count}}    
            </li> 
        </ul>
        <button @click="add">+</button>  
    </div>
</template>

<script>
export default {
    computed:{
        getList(){
            return this.$store.state.foodlist;
        },
        getfood(){
            return this.$store.getters.getfoodName
        }
    },
    methods:{
        add(){
            this.$store.commit('addPrice',5)
        }
    }
};
</script>
還有一個module沒有說,這個先暫時不說了,看下文檔就懂了,接下來說下怎麼通過調接口的方式把數據存到store裏邊,
這裏我們mock下數據https://www.easy-mock.com/註冊賬號後進入:

這裏寫圖片描述

然後找個get請求:
這裏寫圖片描述

點擊編輯接口數據:這裏用這個測試了哈!
https://www.easy-mock.com/mock/5ae4909f24b57d1001c9c190/test

打開main.js

//main.js 引入axios 這裏就不配置baseurl了
import Vue from 'vue'

import App from './App'

import store from './store'

import axios from 'axios'

Vue.prototype.$http = axios

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  components: { App },
  template: '<App/>'
})

Header.vue

// 在created鉤子裏調接口
<script>
export default {
     created(){
       this.$http.get('https://www.easy-mock.com/mock/5ae4909f24b57d1001c9c190/test').then(res => {
           if(res.status==200){
               console.log(res.data.foodlist)
                // 通過 提交mutation 將接口返回的數據作爲參數傳給mutation
                this.$store.commit('getApi',res.data.foodlist)
           } 
        })
    },
};
</script>

在store的js裏接收參數

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

Vue.use(Vuex)
// 通過getApi這個方法 就把接口數據 拿到了,然後再進行賦值
export default new Vuex.Store({
  state:{
    //這裏我們創建個數組
    foodlist:[]
  },
  mutations:{
    // 得到接口數據
    getApi(state,payload){
      // 進行賦值
      state.foodlist = payload;
    }
  },
  actions:{
      Moniyibu(context){
        console.log(context)
        setTimeout(function(){
          context.commit('addPrice',5)
        },2000)
      }
  }
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章