1.结果展示
最后的结果大致是这样的:
样式采用的是element-plus里面卡片和表格;路由主要用在两个切换按钮(商品列表和购物车);操作下面绿色按钮采用的是插槽;数据是放在product.js里面;
2.准备工作
2.1 安装插件
安装插件pinia,vue-router,element-plus
2.2 搭建两个组件
ProduceList.vue 和ShoppingCar.vue
2.3 配置路由
import { createRouter, createWebHistory } from "vue-router";
import ProductList from '../views/ProductList.vue'
import ShoppingCar from '../views/ShoppingCar.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: ProductList
}, {
path: '/productlist',
name: 'productlist',
component: ProductList
}, {
path: '/shoppingcar',
name: 'shoppingcar',
component: ShoppingCar
}
]
})
export default router
2.4 配置首页
两个按钮主要是用来切换路由,展示不同的内容(用router-link;下面的展示内容用router-view展示
<template>
<div>
<el-card class="box-card">
<template #header>
<div class="card-header">
<h1>购物车首页</h1>
<div class="btn">
<router-link to="/productlist">
<el-button style="background-color:skyblue">商品列表</el-button>
</router-link>
<router-link to="/shoppingcar">
<el-button style="background-color:skyblue">购物车</el-button>
</router-link>
</div>
</div>
</template>
<router-view></router-view>
</el-card>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.card-header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
.el-button {
margin-right: 20px;
}
}
</style>
2.5 配置store
import { defineStore } from "pinia";
import { ref } from 'vue'
import { computed } from 'vue';
const useShoppingCarStore = defineStore("shopping-car", () => {
}
return { }
)
export { useShoppingCarStore }
2.6 在main;js中引入store,vue -router和element-plus
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'
import router from './router'
import { createPinia } from 'pinia'
const pinia = createPinia()
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(pinia).use(router).use(ElementPlus).mount('#app')
3.展示商品列表内容
初始化商品列表和购物车列表,以及获取商品列表的方法
store.js
const useShoppingCarStore = defineStore("shopping-car", () => {
//写成函数形式的话,就没有state,getters,actions等形式
//初始化商品列表
const productlist = ref([])
//初始化购物车列表
const shopCarList = ref([])
//初始化商品列表的方法
const getProductList = async () => {
const res = await getProducts()
productlist.value = res
}
return { productlist, getProductList, addShopCarList, shopCarList, totalPrice }
})
ProductList.vue
<template>
<div class="product-list">
<el-table :data="shoppingCarStore.productlist" stripe style="width: 100%">
<el-table-column prop="id" label="序号" align="center" />
<el-table-column prop="title" label="名称" align="center" />
<el-table-column prop="price" label="价格" align="center" />
<el-table-column prop="number" label="库存" align="center" />
<el-table-column prop="address" label="操作" align="center">
<template #default="scope">
<el-button @click="add(scope.row)" type="success">添加到购物车</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { useShoppingCarStore } from '../store'
const shoppingCarStore = useShoppingCarStore()
//调用actions初始化productlist列表
shoppingCarStore.getProductList()
function add(row) {
//console.log(row)
shoppingCarStore.addShopCarList(row)
}
</script>
<style lang="scss" scoped></style>
4.展示购物车列表内容
点击加入购物车按钮要完成两件事,一是修改商品的列表,数量要减少;二是将商品信息添加到购物车
4.1 修改商品的列表,数量要减少
const addShopCarList = (item) => {
const res = productlist.value.find((_item) => {
return _item.id === item.id
})
//1.修改商品列表 点一下商品库存减少1
if (res.number < 1) {
ElMessage.error({
message: '没有库存了!'
})
}
res.number--
//对购物车里的库存列表进行降序排序
shopCarList.value.sort((a, b) => {
return a.id - b.id
})
}
4.2 将商品信息添加到购物车
这里做一个判断,如果没有这个商品,会将整个商品信息添加进去,如果商品已经存在,这时候只需要number++;
//点击按钮的逻辑 1.修改商品列表 2.添加到购物车列表
const addShopCarList = (item) => {
const res = productlist.value.find((_item) => {
return _item.id === item.id
})
//1.修改商品列表 点一下商品库存减少1
if (res.number < 1) {
ElMessage.error({
message: '没有库存了!'
})
}
res.number--
//2.将商品添加到购物车列表
//如果没有这个商品,会将整个商品信息添加进去,如果商品已经存在,这时候只需要number++
const _res = shopCarList.value.find((_item) => {
return _item.id === item.id
})
if (!_res) {
shopCarList.value.push({
id: item.id,
title: item.title,
price: item.price,
number: 1
})
} else {
_res.number++
}
//对购物车里的库存列表进行降序排序
shopCarList.value.sort((a, b) => {
return a.id - b.id
})
}
4.3 结算
//结算商品代码 计算属性
const totalPrice = computed((item) => {
//累加遍历方法reduce
return shopCarList.value.reduce((pre, cur) => {
return pre + cur.price * cur.number
}, 0)
})
4.4 ShoppingCar.vue
<template>
<div>
<el-table :data="shoppingCarStore.shopCarList" stripe style="width: 100%">
<el-table-column prop="id" label="序号" align="center" />
<el-table-column prop="title" label="名称" align="center" />
<el-table-column prop="price" label="价格" align="center" />
<el-table-column prop="number" label="库存" align="center" />
</el-table>
<div v-if="shoppingCarStore.shopCarList.length">
<h2>商品总价是:{{ shoppingCarStore.totalPrice }}</h2>
<el-button type="primary" @click="calc">结算价格</el-button>
</div>
</div>
</template>
<script setup>
import { useShoppingCarStore } from '../store';
import { buyProducts } from '../api/product';
import { ElMessage } from "element-plus";
const shoppingCarStore = useShoppingCarStore()
async function calc() {
const res = await buyProducts()
if (res) {
ElMessage.success({
message: '结算成功!'
})
//变成一个空数组
shoppingCarStore.shopCarList = []
} else {
ElMessage.error({
message: '结算失败!'
})
}
}
</script>
<style lang="scss" scoped></style>
点击结算