• Day46:项目-购物车案例


    购物车案例

    1. 准备工作
      1. 首页默认加载,其余页面懒加载

      2. 调用defineStore方法构建store

      3. 入口main做对应配置,找指南,快速开始,把elementplus引入进来
    1. import { createApp } from "vue";
    2. import { createPinia } from "pinia";
    3. import "./style.css";
    4. import App from "./App.vue";
    5. import router from "./router";
    6. import ElementPlus from "element-plus";
    7. import "element-plus/dist/index.css";
    8. const app = createApp(App);
    9. const pinia = createPinia();
    10. app.use(router);
    11. app.use(pinia);
    12. app.use(ElementPlus);
    13. app.mount("#app");
      1. api就是用来模拟后台接口的

    1. 在app.vue中做购物车首页,头部不进入路由,在头部的底部放RouterView
    2. 给app 的header添加插槽#header,写类名添加样式,头部插槽内的内容不会发生变化
    1. <template>
    2. <div>
    3. <el-card class="box-card">
    4. <template #header>
    5. <div class="card-header">
    6. <h1>购物车首页</h1>
    7. <div class="btn">
    8. <RouterLink to="/productlist">
    9. <el-button type="primary">商品列表</el-button></RouterLink
    10. >
    11. <RouterLink to="/shoppingcar"
    12. ><el-button type="primary">购物车</el-button></RouterLink
    13. >
    14. </div>
    15. </div>
    16. </template>
    17. <RouterView />
    18. </el-card>
    19. </div>
    20. </template>
      1. 写购物车首页的标题
      2. 写el-button:商品列表,购物车。并用routerLink包裹,做一个导航,并为RouterLink添加to页面
    1. 在商品列表页面,写一个el-table,
    1. <template>
    2. <div class="product-list">
    3. <el-table :data="shoppingCarStore.productList" stripe style="width: 100%">
    4. <el-table-column prop="id" label="序号" align="center" />
    5. <el-table-column prop="title" label="商品名称" align="center" />
    6. <el-table-column prop="price" label="商品价格" align="center" />
    7. <el-table-column prop="number" label="库存" align="center" />
    8. <el-table-column prop="address" label="操作" align="center">
    9. <template #default="scope">
    10. <el-button type="success" @click="add(scope.row)">
    11. 添加到购物车
    12. </el-button>
    13. </template>
    14. </el-table-column>
    15. </el-table>
    16. </div>
    17. </template>
    1. 在store中写方法,初始化商品列表和初始化商品数据的方法
    1. import { defineStore } from "pinia";
    2. import { computed, ref } from "vue";
    3. import { getProducts } from "../api/product";
    4. import { ElMessage } from "element-plus";
    5. import { buyProducts } from "../api/product.js";
    6. const useShoppingCarStore = defineStore("shopping-car", () => {
    7. //初始化商品列表数据
    8. const productList = ref([]);
    9. //初始化购物车列表数据
    10. const shopCarList = ref([]);
      1. 一秒钟之后获取到数据(模拟从接口获取数据),
    1. //1s中之后返回数组数据
    2. export const getProducts = async ()=>{
    3. //为了模拟真实的接口请求
    4. await wait(1000)
    5. return products
    6. }
      1. 方法在数据获取的部分有定义。
      2. 把两个需要给视图使用的方法从store中导出,并在商品列表中导入方法
      3. 绑定在table中,
    1. 给table添加按钮
      1. 改变button样式
      2. 绑定add方法,在页面中传参scope.row,代表点选的那一行。(scope代表插槽的作用域)在方法中传参row
    1. <script setup>
    2. import { useShoppingCarStore } from "../store";
    3. const shoppingCarStore = useShoppingCarStore();
    4. shoppingCarStore.getProductList();
    5. function add(row) {
    6. //调用 将数据添加到购物车的方法
    7. shoppingCarStore.addShopCarList(row);
    8. }
    9. </script>
    1. 在store中写给购物车添加数据的方法
      1. 减去商品列表页面的库存:res的item id === row id时,下转判断,判断完自减--
      2. 添加购物车列表页面的商品数量,_res的item id === row id时,下转判断
        1. 在store中定义初始化购物车列表
        2. 判断购物车中是否已经存在这个商品
        3. 如果存在,将商品数量+1(_res.number++
        4. 如果没有,添加一个新商品(起始数量一定是1
      1. 判断当库存<1,写一个提示,商品已经妹有了,存在一秒。
      2. 导出方法并在列表页调用,放在add方法中,add传入的参数为row,指在点选的那一行。
    1. const useShoppingCarStore = defineStore("shopping-car", () => {
    2. //初始化两行
    3. ......
    4. //初始化商品列表数据的方法(使用async方法,没有一大堆回调函数
    5. const getProductList = async () => {
    6. const res = await getProducts();
    7. productList.value = res;
    8. };
    9. // const getProductList = () => {
    10. // getProducts().then((res) => {
    11. // productList.value = res;
    12. // });
    13. // };
    14. //给购物车添加数据的方法
    15. const addShopCarList = (row) => {
    16. //1. 减去商品列表页面的商品库存
    17. const res = productList.value.find((item) => item.id === row.id);
    18. if (res.number < 1) {
    19. ElMessage.error({
    20. message: "没有库存辣!",
    21. duration: 1000,
    22. });
    23. return;
    24. }
    25. res.number--;
    26. //2. 添加购物车列表页面的商品数量
    27. const _res = shopCarList.value.find((item) => item.id === row.id);
    28. //2.1 判断购物车列表数据中是否包含当前的商品 如果包含 让数量自增
    29. //2.2 如果不包含 将这个商品添加到购物车列表
    30. if (!_res) {
    31. shopCarList.value.push({
    32. id: row.id,
    33. title: row.title,
    34. price: row.price,
    35. number: 1,
    36. });
    37. } else {
    38. _res.number++;
    39. }
    40. //给购物车列表中的商品按照id的升序做一个排序
    41. shopCarList.value.sort((a, b) => {
    42. return a.id - b.id;
    43. });
    44. };
    45. ...
    46. return{...addShopCarList,...};
    1. 在购物车列表中写el-table
      1. 引入useshoppingcarstore,并绑定数据.shopCarList
      2. 绑定prop属性,表示绑定了哪个属性
    1. 在store中添加排序功能,商品加入购物车后按照id自动排序,写在_res判断下面
      1. shopCarList.value.sort((a,b) => {})

    getProductsList方法最好使用async和await语法,而不是等价的.then。因为async和await语法不涉及大量的回调函数,也就不用进行大量的回调函数嵌套,处理起来更简单不容易出错。

    1. //初始化商品列表数据的方法
    2. const getProductList = async () => {
    3. const res = await getProducts();
    4. productList.value = res;
    5. };
    6. // const getProductList = () => {
    7. // getProducts().then((res) => {
    8. // productList.value = res;
    9. // });
    10. // };
    1. 写普通的table计算shopCarList里的商品总价
      1. 使用computed计算属性计算商品总价。
      2. const一个totalPrice
    1. const useShoppingCarStore = defineStore("shopping-car", () => {
    2. //初始化商品列表数据
    3. ......
    4. //计算shopcarList里的商品总价
    5. const totalPrice = computed(() => {
    6. //reduce
    7. return shopCarList.value.reduce((pre, cur) => {
    8. return pre + cur.number * cur.price;
    9. }, 0);
    10. });
    11. .....
    12. return {...totalPrice,...};
    13. });
      1. return一个reduce方法,它是一个数组遍历中常用的方法。第一个参数为回调逻辑,第二个参数为累加初始值(大多数为0)

      2. 把商品总价渲染到页面
    1. 在商品列表页写一个结算商品的button,
      1. 绑定点击事件calc(vue2不能直接绑click,需要加字符;vue3的组件绑定会判断是否为原生事件)
      2. 在store中写calc方法
      3. 结算方法已经写在products中,引入到store中。
      4. 该方法通过一个随机数来随机判断结算是否成功。、
      5. 这是一个异步方法,需要async和await
      6. 判断结算是否成功,成功弹出成功,并清空数组;
      7. 结算失败弹出失败,不清空列表,需要再次结算。
    1. const useShoppingCarStore = defineStore("shopping-car", () => {
    2. ......
    3. //结算商品列表的方法
    4. const calc = async () => {
    5. const res = await buyProducts();
    6. if (res) {
    7. ElMessage.success({
    8. message: "结算成功",
    9. duration: 1000,
    10. });
    11. shopCarList.value = [];
    12. } else {
    13. ElMessage.error({
    14. message: "结算失败",
    15. duration: 1000,
    16. });
    17. }
    18. };
    19. return {
    20. ....
    21. calc,
    22. };
    23. });
    1. 购物车中,对结算框v-if判断,如果购物车列表没有数据,则不显示结算框。
    1. <template>
    2. <div class="shopping-car">
    3. <el-table :data="shoppingCarStore.shopCarList">
    4. <el-table-column prop="id" label="序号" align="center" />
    5. <el-table-column prop="title" label="名称" align="center" />
    6. <el-table-column prop="price" label="价格" align="center" />
    7. <el-table-column prop="number" label="数量" align="center" />
    8. </el-table>
    9. <div class="btn" v-if="shoppingCarStore.shopCarList.length">
    10. <h2>商品总价是:{{ shoppingCarStore.totalPrice }}</h2>
    11. <el-button type="primary" @click="calc">结算商品</el-button>
    12. </div>
    13. </div>
    14. </template>
    15. <script setup>
    16. import { useShoppingCarStore } from "../store";
    17. const shoppingCarStore = useShoppingCarStore();
    18. function calc() {
    19. //触发商品结算的方法 calc()
    20. shoppingCarStore.calc();
    21. }
    22. </script>
  • 相关阅读:
    如何在excel表中实现单元格满足条件时整行变色?
    ⚡性能优化之首屏秒开
    Java标识符和关键字
    保护服务器免受攻击:解析攻击情境与解决之道
    使用OpenResty+Lua实现灰度测试(金丝雀)
    简谈设计模式之建造者模式
    【深度学习】基于卷积神经网络(tensorflow)的人脸识别项目(三)
    UML类图以及常用集合
    设计原则——合成复用原则
    工控机通过485modbus转profinet网关与温度智能表通讯案例
  • 原文地址:https://blog.csdn.net/albedo_102/article/details/132928004