【Vue2项目(尚品汇前台)】(五)Shopcar购物车模块搭建

一、加入购物车

当我们点击加入购物车按钮之后,要返回一个商品个数和购物的商品信息,那我们就需要调用添加到购物车接口
在这里插入图片描述
分析一下会发现,我们只是为了返回一个成功或者失败的结果,那用promise不是更好吗,所以我们进行改进
在这里插入图片描述

二、导入加入购物车成功页面组件 + 配置路由

在这里插入图片描述

三、购物成功页面拿数据

1、路由传递参数

当我们点击加入购物车之后,加入成功页面要拿到商品的信息和购买的个数,然后要体现在url地址栏中,如果按照之前那么写的话,地址栏会非常的丑,信息不明显,所以要改进,这里用到了会话存储的方法

本地存储:持久化
会话存储:并非持久
本地存储|会话存储:一半存储的是字符串
产品信息的数据【比较复杂:skuInfo】,通过会话存储(不持久化,会话结束数据会消失)

购物车添加成功这个页面并非需要一直持久存在,所以选择会话存储
在这里插入图片描述

因为传递的是一个对象,所以要用转换为字符串
在这里插入图片描述
在AddCartSuccess.js文件中进行接收

AddCartSuccess.js

computed:{
      skuInfo(){
        return JSON.parse(sessionStorage.getItem('SKUINFO'));
      }
    }

2、渲染数据

<div class="right-info">
      <p class="title">{{skuInfo.skuName}}</p>
      <p class="attr">{{ skuInfo.skuDesc }} 数量:{{$route.query.skuNum}}}</p>
</div>

四、添加购物车成功页面两个按钮的动态绑定

在这里插入图片描述
给查看商品详情按钮设定声明式导航,回退到商品页面并带上商品id参数,所以使用动态式的:to

在这里插入图片描述

五、获取购物车信息接口

在这里插入图片描述

在这里插入图片描述
获取接口成功,但是我们看到没有数据,这是为什么呢?
用户有非常多,每一个人都应该有自己的购物车,但是系统不能分辨哪一个商品是谁加入购物车的,才会出现没有数据的现象。

解决方案:uuid

六、uuid游客身份获取购物车数据

UUID全称:Universally Unique Identifier,即通用唯一识别码。

uuid_token.js
import {v4 as uuidv4} from 'uuid'
//要生成一个随机字符串,且每次执行不能发生变化,游客身份持久存储
export const getUUID = ()=>{
    //先从本地存储获取uuid(看一下本地存储里面是否有)
    let uuid_token = localStorage.getItem('UUIDTOKEN');
    //如果没有
    if(!uuid_token){
        //我生成游客临时身份
        uuid_token = uuidv4();
        //本地存储存储一次
        localStorage.setItem('UUIDTOKEN',uuid_token);
    }
    return uuid_token;
}

切记一定要有返回值,要不然是undefined!!

创建一个uuid_token.js文件,在这个文件里面封装一个生成随机,且能存储的的游客身份
在这里插入图片描述
在detail仓库里使用这个函数方法

在request.js中设置请求头

//在当前模块引入store
import store from '@/store'

//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {
    //config:配置对象,对象里面有一个属性很重要,headers请求头
    //进度条开始动
    if (store.state.detail.uuid_token) {
        //请求头添加一个字段(userTempId):这个字段已经是和后台商量好了
        config.headers.userTempId = store.state.detail.uuid_token
    }
    nprogress.start();
    return config;
});

七、动态绑定数据

在这里插入图片描述

定义两个函数来计算总价和全选按钮

//计算购买产品的总价
    totalPrice() {
      let sum = 0;
      this.cartInfoList.forEach((item) => {
        sum += item.skuNum * item.skuPrice;
      });
      return sum;
    },
    //判断底部复选框是否勾选[全部产品都选中,才勾选]
    isAllCheck() {
      // every 只要全部元素里有一个不是1,则为假,全为真才真
      return this.cartInfoList.every((item) => item.isChecked == 1);
    },

在这定义了三个形参type,disNum,cart
type为了区分这三个元素
disNum 形参: + 变化量(1) -变化量(-1) input最终的个数
cart:哪一个产品

//修改某一个产品的个数
    handler(type, disNum, cart) {
      //type为了区分这三个元素
      //disNum 形参: + 变化量(1)  -变化量(-1)   input最终的个数
      //cart:哪一个产品
      //向服务器发请求,修改数量
      switch (type) {
        //加号
        case "add":
          disNum = 1;
          break;
        case "minus":
          //判断产品的个数大于1,才可以传递给服务器-1
          if (cart.skuNum > 1) {
            disNum = -1;
          } else {
            //产品的个数小于等于1
            disNum = 0;
          }
          break;
        // disNum = cart.skuNum > 1 ? -1 : 0; //写成三元表达式
      }

这里已经对三个按钮设置了判断,接下来就要通知服务器,把新的价格信息拿到,并渲染到页面上

//修改某一个产品的个数
    async handler(type, disNum, cart) {
      //type为了区分这三个元素
      //disNum 形参: + 变化量(1)  -变化量(-1)   input最终的个数
      //cart:哪一个产品
      //向服务器发请求,修改数量
      switch (type) {
        //加号
        case "add":
          disNum = 1;
          break;
        case "minus":
          //判断产品的个数大于1,才可以传递给服务器-1
          if (cart.skuNum > 1) {
            disNum = -1;
          } else {
            //产品的个数小于等于1
            disNum = 0;
          }
          break;
        // disNum = cart.skuNum > 1 ? -1 : 0; //写成三元表达式
        case "change":
          //用户输入进来的最终量,非法的(带有汉字),带给服务器数字
          if (isNaN(disNum) || disNum < 1) {
            disNum = 0;
          } else {
            disNum = parseInt(disNum) - cart.skuNum;
          }
          break;
      }
      //派发action
      try {
        //代表的是成功
        await this.$store.dispatch("addOrUpdateShopCart", {
          skuId: cart.skuId,
          skuNum: disNum,
        });
        //再一次获取服务器最新的数据进行展示
        this.getData();
      } catch (error) {}

这一块的代码看一看吧,思路我还有点懵,后面要回来多看看
在这里插入图片描述

八、删除商品

这里要用到删除购物车的接口,还是老手法
我们看到接口信息里的data没有数据,说明不需要返回信息,只需要判断是否成功

//删除购物车产品的接口
export const reqDeleteCartById = (skuId) => requests({
    url: `/cart/deleteCart/${skuId}`,
    method: 'delete'
})
async DeleteCartListById({ commit }, skuId) {
        let result = await reqDeleteCartById(skuId);
        if (result.code == 200) {
            return 'ok'
        } else {
            return Promise.reject(new Error('faile'))
        }
    }

给删除按钮定义一个自定义事件

 <a class="sindelet" @click="deleteCartById(cart)">删除</a>

点击删除之后要记得更新数据

//删除某一个产品的操作
    async deleteCartById(cart){
      try {
        await this.$store.dispatch('DeleteCartListById',cart.skuId);
        this.getData();
      } catch (error) {
        alert(error.message);
      }

九、bug

当用户点减少数量太快,会显示负数,所以这一块我们要用到节流,重新复习一下防抖和节流哈哈

先引入throttle

import throttle from 'lodash/throttle'
 handler: throttle(async function (type, disNum, cart) {
      //type为了区分这三个元素
      //disNum 形参: + 变化量(1)  -变化量(-1)   input最终的个数
      //cart:哪一个产品
      //向服务器发请求,修改数量
      switch (type) {
        //加号
        case "add":
          disNum = 1;
          break;
        case "minus":
          //判断产品的个数大于1,才可以传递给服务器-1
          if (cart.skuNum > 1) {
            disNum = -1;
          } else {
            //产品的个数小于等于1
            disNum = 0;
          }
          break;
        // disNum = cart.skuNum > 1 ? -1 : 0; //写成三元表达式
        case "change":
          //用户输入进来的最终量,非法的(带有汉字),带给服务器数字
          if (isNaN(disNum) || disNum < 1) {
            disNum = 0;
          } else {
            disNum = parseInt(disNum) - cart.skuNum;
          }
          break;
      }
      //派发action
      try {
        //代表的是成功
        await this.$store.dispatch("addOrUpdateShopCart", {
          skuId: cart.skuId,
          skuNum: disNum,
        });
        //再一次获取服务器最新的数据进行展示
        this.getData();
      } catch (error) {}
    }),

十、修改产品状态

第一步还是调用接口,然后定义自定义事件,派发action,更新数据

//修改商品的选中状态
export const reqUpdateCheckedById = (skuId,isChecked) => requests({
    url: `/cart/checkCart/${skuId}/${isChecked}`,
    method: 'get'
})
async updateCheckedByid({ commit }, skuId, isChecked) {
        let result = await reqUpdateCheckedById(skuId, isChecked);
        if (result == 200) {
            return 'ok'
        } else {
            return Promise.reject(new Error('false'))
        }
    }
<input type="checkbox" name="chk_list"  :checked="cart.isChecked == 1" @change="updateCheckted(cart, $event)" />

这里我们试着打印一下选中和未选中时,传回的是一个布尔值true和false,但是我们需要的是0或者1来判断,所以我们要进行一个判断

let isChecked = event.target.checked ? "1" : "0";

派发action

this.$store.dispatch("updateCheckedById", {
        skuId: cart.skuId,
        isChecked,
      });

但是这里我们还要判断是否成功,所以用try…catch…

//修改某个产品的勾选状态
    async updateCheckted(cart, event) {
      //带给服务器的参数isChecked 不是布尔值,应该是1 或者 0
      try {
        let isChecked = event.target.checked ? "1" : "0";
        await this.$store.dispatch("updateCheckedById", {
          skuId: cart.skuId,
          isChecked,
        });
        this.getData();
      } catch (error) {
        //如果失败提示
        alert(error.message);
      }
    },

十一、全部商品的勾选状态修改

在这里插入图片描述
给按钮绑定了自定义事件,但是在这个回调函数里我们没办法收集到一些有用的数据,因为没有删除全部选中的商品接口,无法派发action,那怎么办呢

//这个回调函数咱门没办法收集到一些有用数据
    async deleteAllCheckedCart() {
      try {
        await this.$store.dispatch("deleteAllCheckedCart");
        //  再次发送请求
        this.getData();
      } catch (error) {
        console.log(error.message);
      }
    },

回到shopcart仓库中,这里面有我们需要的数据,那一个仓库里应该如何传递数据,从state里把其他的数据捞出来,捞出来每一个商品的isChecked,看是否等于1,等于1就派发action到deleteCartListBySkuId,不为1就为空,然后用promise.all判断

promise.all(),其中有一个为假就返回false

 //删除全部勾选的产品
    deleteAllCheckedCart({ dispatch, getters }) {
        //context:小仓库,commit【提交mutations修改state】 getters【计算属性】 dispatch【派发action】 state【当前仓库数据】
        let PromiseAll = [];
        //获取购物车中全部的产品(是一个数组)
        getters.carList.cartInfoList.forEach((item) => {
            let Promise =
                item.isChecked == 1 ?
                dispatch("deleteCartListBySkuId", item.skuId) :
                "";
            //将每一次返回的Promise添加到数组当中
            PromiseAll.push(Promise);
        });
        //只要全部的p1|p2....都成功,返回结果即为成功
        //如果有一个失败,返回即为失败结果
        return Promise.all(PromiseAll);
    },
//修改全部产品的状态
    async updateAllCartChecked(event) {
      let isChecked = event.target.checked ? "1" : "0";
      // console.log(checked);
      try {
        await this.$store.dispatch("updateAllCartChecked", isChecked);
        this.getData();
      } catch (error) {
        console.log(error.message);
      }
    },

十二、总结

  1. UUID
  2. 修改产品的数量
  3. 删除某一产品的接口
  4. 某一个产品的勾选状态切换
  5. 防抖 节流 复习
  6. 存储
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值