參考官方文檔
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}
]
}
})
準備兩個組件(名字你隨意?。?/h3>
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插件的看的很清楚貼個圖
20180502231737513.png
// 這里也是接受傳參的,修改代碼傳個參數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
});
}
}
1.png
mutation 異步操作出現的問題
上邊說過,mutation里的方法不推薦進行異步操作,那會出現什么問題,
這里我們用延時模擬個異步,我們點擊按鈕進行+5的操作,2秒后讓頁面數據改變
打開store下的js文件
// 模擬延時2秒
mutations:{
// 定義一個增加價格的方法
addPrice(state,num){
// 先遍歷數組,獲取到價格屬性
state.foodlist.forEach(e => {
setTimeout(function(){
e.price +=num;
},2000) //延時2秒
});
}
}
這時候你在頁面中點擊按鈕一次,過了兩秒,數據改變了,當你連點時,你會發現你都不點了,數據還在頁面中慢慢變化,
這顯然不是我們想要的,這時候你打開控制臺,你會看到方法都執行了,數據還沒有變化,知道運行到最后一次執行的時
候,數據才變化完,這個時候我們就要用另一個屬性了action
2.png
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>
文章來源--https://blog.csdn.net/qq_36407748/article/details/80174272
// 在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>
<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個方法就只用一個組件測試了!其它組件用法都一樣的
// 上邊這種方法雖然也可以拿到數據,但官方推薦使用計算屬性的方式獲取數據
<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>
這里不先說getter,因為很好明白,state存數據,那getter看名字就知道是取數據,因為已經有$store.state可以
取到數據了,我們等會說getter,這里我們說改變數據,在組件內,來自store的數據只能讀取,那我們肯定想怎么改
state里的數據,而修改store里的數據的唯一途徑就是顯示的提交mutation,啥意思??!看不懂最后一句,沒有關系,
我們知道你有改數據的需求的地方,只會在某一個組件內,而你不可能手動去store里改,因為state里的數據都是接口
請求下來的,那么怎么改呢,我們需要用$store.commit(),官方解釋的這個方法是在組件內向store里顯示提交mutation
說白了,就是在你的mutation里先定義好了一個操作state里的數據的方法,然后在你的組件里調一下你定義
-----------------------------------------------------
在mutation里那個的方法名,不過需要注意的是mutation里的方法不推薦進行異步操作,這個我們等會說
-----------------------------------
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
});
}
}
})
// 準備一個點擊事件(樣式代碼就不貼了)
<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>
20180502231737513.png
// 這里也是接受傳參的,修改代碼傳個參數5
<script>
export default {
computed:{
getList(){
return this.$store.state.foodlist;
}
},
methods:{
add(){
this.$store.commit('addPrice',5)
}
}
};
</script>
// mutation 默認接收的第一個參數就是state
mutations:{
// 定義一個增加價格的方法
addPrice(state,num){
// 先遍歷數組,獲取到價格屬性
state.foodlist.forEach(e => {
//這里得到每一個對象
//console.log(e)
e.price +=num; //每次點擊+5
});
}
}
1.png
上邊說過,mutation里的方法不推薦進行異步操作,那會出現什么問題,
這里我們用延時模擬個異步,我們點擊按鈕進行+5的操作,2秒后讓頁面數據改變
// 模擬延時2秒
mutations:{
// 定義一個增加價格的方法
addPrice(state,num){
// 先遍歷數組,獲取到價格屬性
state.foodlist.forEach(e => {
setTimeout(function(){
e.price +=num;
},2000) //延時2秒
});
}
}
這時候你在頁面中點擊按鈕一次,過了兩秒,數據改變了,當你連點時,你會發現你都不點了,數據還在頁面中慢慢變化,
這顯然不是我們想要的,這時候你打開控制臺,你會看到方法都執行了,數據還沒有變化,知道運行到最后一次執行的時
候,數據才變化完,這個時候我們就要用另一個屬性了action
2.png
action和muation很像,只不過不同的是action里提交的mutation,啥意思?
就是在action屬性里調用的是mutation里的方法,而且只能對mutation進行操作
// 添加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)
}
}
})
// 在組件內觸發 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也是獲取數據的,但它里邊的數據通常都是處理過的數據
比如有這樣一個需求,我們獲取state里食物價格大于10的數據
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
});
}
}
})
// 依舊寫在計算屬性里 使用 $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>