前言
如果你使用vue开发项目却没有用vuex那么项目开发成本会变高且慢,简单的项目可以不推荐使用vuex
什么是VUEX
官网解释的很清楚:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
自我理解,vuex是用来管理组件之间的相互通信。 组件之间的通信有几种方式,父子组件通信可以通过props传值,非父子组件可以通过中间事件进行bus进行通信; 项目变复杂时使用上面的方式会感到很无力,vuex此时就是最好的选择!
从一个例子开始
用vuex实现简单购物车的功能
1.首先来看目录结构(详细的不再赘述)
我们通过三个组件来实现购物车的基本功能,product组件用来展示商品信息(UI引用element-ui) product组件代码
<template>
<div class="prodcut">
<h4 style="text-align: center">商品信息</h4>
<el-table style="width: 900px;margin: 0 auto":data="shoplist">
<el-table-column prop="id" label="id" width="180"></el-table-column>
<el-table-column prop="name" label="名称" width="180"></el-table-column>
<el-table-column prop="price" label="价格"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" size="small">添加购物车</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'product',
data() {
return {
shoplist: [{
id: 11,
name: '大鼓米线',
price: 27,
}, {
id: 22,
name: '卤道卤香',
price: 16
}, {
id: 33,
name: '谷田稻香',
price: 24
}, {
id: 44,
name: '米饭',
price: 2
}],
};
},
};
</script>
cart组件展示添加购物车商品信息
<template>
<div class="cart">
<h4 style="text-align: center">已选商品</h4>
<el-table style="width: 900px;margin: 0 auto"
:data="cartProducts"
>
<el-table-column
prop="id"
label="id"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="名称"
width="180">
</el-table-column>
<el-table-column
prop="price"
label="价格">
</el-table-column>
<el-table-column
prop="num"
label="数量">
</el-table-column>
<el-table-column
label="操作">
<template slot-scope="scope">
<el-button type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'cart',
data() {
return {
cartProducts: [],
};
},
};
</script>
info组件展示总价格和总数量
<template>
<div class="info">
<el-row style="width: 900px;margin: 15px auto 0;text-align: center;line-height: 40px;">
<el-col :span="8" style="background-color: #ccc">总数:</el-col>
<el-col :span="8" style="background-color: #ccc">总价:</el-col>
<el-col :span="8"><el-button type="danger" plain style="width: 100%">清空购物车</el-button></el-col>
</el-row>
</div>
</template>
<script>
export default {
name:'info',
data(){
return {}
},
}
</script>
然后在app.vue中调用上面三个组件
<template>
<div id="app" style="height: 100%">
<h3 style="text-align: center">Vuex购物车demo</h3>
<!-- 商品列表 -->
<product></product>
<!-- 购物车列表 -->
<cart></cart>
<!-- 统计 -->
<info></info>
</div>
</template>
<script>
import product from './components/product';
import cart from './components/cart';
import info from './components/info';
export default {
name: 'app',
components: {
product,
cart,
info
}
}
</script>
store官方目录结构如图
本例store目录—-store/index.js
// 组装模块并导出 store 的地方
import Vue from 'vue';
import Vuex from 'vuex';
import cart from './modules/cart';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
cart,
},
// strict: process.env.NODE_ENV !== 'production', // 严格模式
});
store/modules/cart.js
//初始化数据(可以看作是vue实例化中的data)
const state = {};
//getter 抛出去的数据(可以看作vue实例化中的计算属性)
const getters = {};
//action 异步的操作(类似于 mutation,但提交的是 mutation)
const actions = {};
//mutation(类似于事件,必须是同步操作)
const mutations = {};
export default {
state,
mutations,
actions,
getters,
};
2.目录结构完成接下来就要实现功能
来看product组件中的功能,需要实现点击添加购物车的功能
首先将product中的shoplist移到store中的cart.js中
修改 cart.js 中的state
const state = {
//商品列表
shoplist: [{
id: 11,
name: '大鼓米线',
price: 27,
}, {
id: 22,
name: '卤道卤香',
price: 16
}, {
id: 33,
name: '谷田稻香',
price: 24
}, {
id: 44,
name: '米饭',
price: 2
}],
//添加到购物车的商品(已选商品)
added:[]
}
我们需要将shoplist从state 中派生出出来,需要用到getters(如果很多组件共享状态不需要每个组件都复制一个方法)
//通过方法访问
const getters = {
//商品列表
shoplist:state => state.shoplist,
}
如何在组件中拿到shoplist,可以直接通过 store.getters.shoplist获取,官方提供了一种更为 简便的方法mapGetters 辅助函数(getters很多的情况下优势就会体现)mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
//引入mapGetters
import {mapGetters} from "vuex";
export default {
name: 'product',
data() {
return {}
},
//第一种方法使用对象展开运算符将
// computed: {
// ...mapGetters(['shoplist'])
// },
//第二种方法使用对象形式
computed:mapGetters({
shoplist:'shoplist'
}),
}
现在需要在product.vue中实现添加购物车的操作
<el-button type="text" size="small" @click='addToCart(scope.row)'>添加购物车</el-button>
在cart.js中的actions编写addToCart方法
const actions = {
//添加购物车
addToCart({commit},product){
commit('add',{
id:product.id
})
},
}
actions提交的是mutation所以从action分发出来的方法需要mutation’接收’
const mutations = {
//添加到购物车操作
add(state,{id}){ //解构id
let record = state.added.find(n=>n.id == id);
if(!record){
state.added.push({
id,
num:1
})
}else {
record.num++
}
console.info(record,state.added)
},
}
同样组件引用action中的方法有mapActions的辅助函数
import {mapGetters,mapActions} from "vuex";
export default {
name: 'product',
data() {
return {}
},
//第一种方法使用对象展开运算符将
computed: {
...mapGetters(['shoplist'])
},
//第二种方法使用对象形式
//computed:mapGetters({
// shoplist:'shoplist'
//}),
methods: {
...mapActions(['addToCart'])
}
}
点击添加购物车需要将数据传到cart组件中,现在修改cart.js文件
const getters = {
//商品列表
shoplist:state => state.shop_list,
//购物车的列表
cartProducts:state=>{
return state.added.map(({id,num})=>{ //在actions中只有id和num的字段
//在原始数据数据上面进行刷选,这里通过id来匹配
let product = state.shop_list.find(n=>n.id == id)
return {
...product,
num
}
})
},
}, cart组件拿到product组件添加的数据
import { mapGetters} from "vuex";
computed: {
...mapGetters(['cartProducts’])
},
至此,我们已经实现添加将商品添加到购物车的功能,接下来需要实现删除功能。 在cart组件中添加delProduct方法
<el-button type="text" size="small" @click="delProduct(scope.row)">删除</el-button>
同样在cart.js中分发action
const actions = {
//添加到购物车操作
addToCart({commit},product){
commit('add',{
id:product.id
})
},
//删除购物车的指定的商品
delProduct({commit},product){
commit('del',product)//commit del的方法
}
}
mutations接收
const mutations = {
//添加到购物车操作
add(state,{id}){
let record = state.added.find(n=>n.id == id);
if(!record){
state.added.push({
id,
num:1
})
}else {
record.num++
}
},
//删除购物车的指定的商品
del(state,product){
state.added.forEach((n,i)=>{
if(n.id == product.id){
//找到下标值
state.added.splice(i,1)
}
})
},
}
cart组件调用
import { mapGetters,mapActions} from "vuex";
methods:{
...mapActions(['delProduct'])
}
购物车添加删除功能已全部实现,我们还需要实现计算商品的总数,总价以及清空购物车的功能
在getters中操作
const getters = {
//商品列表
shoplist:state => state.shop_list,
//购物车的列表
cartProducts:state=>{
return state.added.map(({id,num})=>{
let product = state.shop_list.find(n=>n.id == id)
return {
...product,
num
}
})
},
//计算总价
totalPrice:(state,getters)=>{ //getter中可以调用getter里面的方法,文档有介绍
let total = 0;
getters.cartProducts.forEach(n=>{
total += n.price * n.num
})
return total;
},
//计算总数量
totalNum:(state,getters)=>{
let total = 0;
getters.cartProducts.forEach(n=>{
total += n.num
})
return total;
},
}
在info组件中调用
import { mapGetters } from 'vuex'
computed:{
...mapGetters(['totalPrice','totalNum'])
}
清空购物车,直接将added数组清空即可
info组件中添加方法
<el-button type="danger" plain style="width: 100%" @click="clearAllCart">清空购物车</el-button>
同样需要在action中分发
const actions = {
//添加到购物车操作
addToCart({commit},product){
commit('add',{
id:product.id
})
},
//清除购物车
clearAllCart({commit}){
commit('clearAll’) //分发一个clearAll事件,不带参数进行
},
}
mutations接受
const mutations = {
//添加到购物车操作
add(state,{id}){
let record = state.added.find(n=>n.id == id);
if(!record){
state.added.push({
id,
num:1
})
}else {
record.num++
}
// console.info(record)
},
//清除购物车
clearAll(state){
state.added = []
},
}
info组件中调用
import { mapGetters, mapActions } from 'vuex'
methods: {
...mapActions(['clearAllCart'])
},
Vuex实现简单购物车功能已实现,vuex多使用几次就可以理通各个模块所负责的功能