创建模块和组件
模块
在store文件夹下创建modules模块文件夹,在模块文件夹下分别创建cart.js、products.js模块,并将两个模块和store中的index.js关联起来,在index.js中将两个模块导入,并在modules属性中将两个模块挂载。
index.js
//导入
import cart from './modules/cart';
import products from './modules/products';
//挂载
modules: {
cart,
products
}
组件
因为案例并不涉及路由跳转,直接在components中创建商品组件ProductList和购物车组件ShoppingCart。
后台数据
在项目目录下创建vue.config.js文件,配置devServer,重启项目,同时获取该后台数据需要发起请求,需安装axios,终端输入npm i axios -s进行安装。
注意:每次该文件进行修改都需要重启项目才能生效。
vue.config.js
const products = [{
id: 1,
title: 'Redmi 10',
price: 2200,
inventory: 12
}, {
id: 2,
title: 'Redmi 10 pro',
price: 2800,
inventory: 18
}, {
id: 3,
title: 'Redmi 10 max',
price: 3200,
inventory: 8
}]
module.exports = {
devServer: {
before(app, serve) {
app.get('/api/products', (req, res) => {
res.json({
results: products
})
})
}
}
}
模块和组件开发
products.js模块
//导入axios
import axios from "axios"
export default {
namespaced: true,
state: {
products: []
},
getters: {},
mutations: {
//从后台拿取数据
getProductsFromServe(state, products) {
state.products = products;
},
//添加到购物车,库存减一
decreaseProductsInventory(state, {
id
}) {
//查找添加到购物车的商品的id与商铺中商品id是否相等,并对其进行库存减一
const product = state.products.find(item => item.id === id);
product.inventory--;
}
},
actions: {
//从后台获取数据
async getProductsFromServe({
commit
}) {
//发送请求 获取数据 提交mutations
try {
const res = await axios.get('/api/products');
//console.log(res.data.results);
const results = res.data.results;
//提交
commit('getProductsFromServe', results);
} catch (error) {
console.log(error);
}
}
}
}
cart.js模块
在当前模块获取其他模块的状态,需要rootState参数,在当前模块提交到另一个模块时需要{root:true}参数
export default {
namespaced: true,
state: {
cartList: [],
count: 0
},
getters: {
//获取购物车的数据
//rootState 获取根节点对象index.js,通过它在cart模块中获取product模块中的商品信息
//在一个模块获取另一个模块的数据时,需要rootState
getCartList(state, getters, rootState) {
//console.log(rootState);
//{id,quantity} 对cartList中的每一项进行解构
return state.cartList.map(({
id,
quantity
}) => {
//购物车中商品的id与当前商品的id是否一样
const product = rootState.products.products.find(item => item.id === id);
return {
title: product.title,
price: product.price,
quantity: quantity
}
})
},
//通过 getters 能够获取 getters 中的方法
//计算总价
getTotalPrice(state, getters) {
return getters.getCartList.reduce((total, product) => {
return total += product.price * product.quantity
}, 0)
}
},
mutations: {
//第一次添加商品到购物车
pushProductToCart(state, {
id,
quantity
}) {
state.cartList.push({
id,
quantity
})
},
//购物车中已有数据,只改变当前的数量
addCartItemQuantity(state, {
id
}) {
//在购物车中查找当前添加的商品,进行数量+1
const product = state.cartList.find(item => item.id === id);
product.quantity++;
}
},
actions: {
//添加商品到购物车
addProductToCart({
commit,
state
}, product) {
//console.log(product);
//判断是否有库存
if (product.inventory > 0) {
//判断是否是第一次添加
const cartItem = state.cartList.find(item => item.id === product.id);
//console.log(cartItem);
//如果没有找到,则是第一次添加
if (!cartItem) {
commit('pushProductToCart', {
id: product.id,
quantity: 1
})
} else {
//购物车中已添加该商品,进行数量+1
commit('addCartItemQuantity', {
id: product.id
})
}
//库存减1,提交到products模块中的decreaseInventory方法
//当从一个模块提交到另一个模块时,一定要加上第三个参数 {root:true}
commit('products/decreaseProductsInventory', {
id: product.id
}, {
root: true
});
}
}
}
}
ProductList组件
<template>
<div>
<h2>商铺</h2>
<ul>
<li>{{product}} - {{price}} - {{inventory}}</li>
<li v-for="product in products" :key="product.id">
{{product.title}} - {{product.price | currency}} - {{product.inventory}}
<!-- 库存为0时,禁用按钮 -->
<button :disabled="!product.inventory" @click="addProductToCart(product)">添加到购物车</button>
</li>
</ul>
</div>
</template>
<script>
//导入辅助函数
import { mapState, mapActions } from "vuex";
export default {
name: "ProductList",
data() {
return {
product: "产品",
price: "价格",
inventory: "库存",
};
},
computed: {
//获取products模块中的products状态
...mapState("products", ["products"]),
},
created() {
//触发products模块中的方法获取后台数据,对列表进行渲染
this.$store.dispatch("products/getProductsFromServe");
},
methods: {
//获取cart模块的addProductToCart方法
...mapActions("cart", ["addProductToCart"]),
},
};
</script>
<style scoped>
</style>
ShoppingCart组件
<template>
<div>
<h2>我的购物车</h2>
<ul>
<li
v-for="(item,index) in getCartList"
:key="index"
>{{item.title}} - {{item.price | currency}} x {{item.quantity}}</li>
</ul>
<!-- currency添加过滤器,对价格进行过滤 -->
<h2>总价:{{getTotalPrice|currency}}</h2>
</div>
</template>
<script>
//导入辅助函数
import { mapGetters } from "vuex";
export default {
name: "ShoppingCart", //组件名,注册全局组件时使用
computed: {
...mapGetters("cart", ["getCartList", "getTotalPrice"]),
},
};
</script>
<style scoped>
</style>
注册全局组件、过滤器
需要在main.js中进行注册,main.js是整个项目的入口文件。
注册全局组件
首先导入组件,然后进行注册,既可以命名也可以通过组件抛出的name属性命名。
//导入组件
import ShoppingCart from '@/components/ShoppingCart'
//全局注册组件
//Vue.component('ShoppingCart', ShoppingCart)
//使用组件抛出的组件名
Vue.component(ShoppingCart.name, ShoppingCart)
注册全局过滤器
//全局注册过滤器
Vue.filter('currency', (value) => '¥' + value)
Vuex中导入插件
在store文件夹下的index.js中导入
//导入日志插件
import createLogger from 'vuex/dist/logger'
然后在通过plugins属性进行挂载
export default new Vuex.Store({
//日志插件 相当于集成了 Vue Devtools
plugins: [createLogger({
// 自动展开记录的 mutation
collapsed: false
})],
})