Skip to content

购物车页面

购买数量加减操作

  1. 在Details页面中修改:src->pages->Details->index.vue
vue
<template lang="">
    <div>
		<div class="cartWrap">
            <!-- 购物车数量的添加 -->
            <div class="controls">
                <!-- 方式1:使用方法控制数量 -->
                <input @change="upBuyNumByAntiShake" autocomplete="off" class="itxt" :value="buyNum">
                <!-- 通过类名来判断是否是假发还是减法 -->
                <a href="###" class="['plus',{disabled:buyNum===200}]" @click.prevent="changeBuyNum">+</a>
                <a href="###" class="['mins',{disabled:buyNum===1}]" @click.prevent="changeBuyNum">-</a>
            </div>
            <div class="add">
                <a href="###" target="_blank">加入购物车</a>
            </div>
        </div>
    </div>
</template>
<script>
...
import { goodsNumReg } from "@/utils/reg";
export default {
    name:"Details",
    data(){
        return{
            // 购买的数量
            buyNum:1
        }
    },
    methods:{
        // 更新购买的数量
        upBuyNum(e){
            // 获取e的值
            const num = e.target.value.trim()/1;
            // 如果输入的数值在正则表达式的范围内,则更新数据,否则使用旧的值
            if (goodsNumReg.test(num)){
                this.buyNum = num;
            }else{
                e.target.value = this.buyNum
            }
        },
        // 加减法函数
        changeBuyNum(e){
            // 减法
            if(e.target.classList.contains("mins")){
                if(this.buyNum===1) return;
                this.buyNum--;
            } else if (e.target.classList.contains("plus")) {
                if (this.buyNum===200) return;
                this.buyNum++;
            }
        }
    },
}
</script>
<style lang="">
    
</style>
  1. 导入正则表达式来限制输入的数值范围在1-200之间:src->utils->reg.js
js
//校验商品购买数量的正则表达式
export const goodsNumReg = /^([1-9]|[1-9]\d|1\d{2}|200)$/
//手机号正则
export const phoneReg = /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/
//验证码正则
export const codeReg = /^\d{6}$/
//密码正则
export const pwdReg = /^\w{6,21}$/
  1. 应用正则表达式:src->pages->Details->index.vue
js
import {goodsNumReg} from "@/utils/reg";

实现防抖

  1. 在Details页面中修改:src->pages->Details->index.vue
vue
<template lang="">
    <div>
        <div class="cartWrap">
            <!-- 购物车数量的添加 -->
            <div class="controls">
                <!-- 方式1:使用方法upBuyNum控制数量 -->
                <!-- 方式2:使用防抖upBuyNumByAntiShake控制数量 -->
                <!-- 方式3:使用方法upBuyNumByLodash控制数量 -->
                <input @change="upBuyNumByLodash" autocomplete="off" class="itxt" :value="buyNum">
                <!-- 通过类名来判断是否是假发还是减法 -->
                <a href="###" class="['plus',{disabled:buyNum===200}]" @click.prevent="changeBuyNum">+</a>
                <a href="###" class="['mins',{disabled:buyNum===1}]" @click.prevent="changeBuyNum">-</a>
            </div>
            <div class="add">
                <a href="###" target="_blank">加入购物车</a>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    ...
    methods:{
        // 更新购买的数量
        upBuyNum(e){
            // 获取e的值
            const num = e.target.value.trim()/1;
            // 如果输入的数值在正则表达式的范围内,则更新数据,否则使用旧的值
            if (goodsNumReg.test(num)){
                this.buyNum = num;
            }else{
                e.target.value = this.buyNum
            }
        },
        // 更新购买的数量(原生防抖)防抖是多次触发执行最后一个,节流是多次触发执行第一个
        upBuyNumByAntiShake(e){
            // 如果有定时器,先清除以前定时器
            if (this.timer){
                clearTimeout(this.timer);
            }
            // 声明一个单次定时器,1秒延迟后执行回调函数
            this.timer = setTimeout(()=>{
                // 获取input输入框的数值
                const num = e.target.value.trim() / 1;
                if (goodsNumReg.test(num)) {
                    this.buyNum = num;
                } else {
                    e.target.value = this.buyNum;
                }
            },1000)
        },
        // 使用第三方lodash实现防抖
        upBuyNumByLodash(){
			
        },
        // 加减法函数
        changeBuyNum(e){
            // 减法
            if(e.target.classList.contains("mins")){
                if(this.buyNum ===1 ) return;
                this.buyNum--;
            } else if (e.target.classList.contains("plus")) {
                if (this.buyNum === 200) return;
                this.buyNum++;
            }
        }
    },
}
</script>
  1. 使用第三方实现防抖 lodash
js
npm install lodash
import {debounce} from "lodash"

src->pages->Details->index.vue
// 使用
    methods:{
        // 更新购买的数量
        upBuyNum(e){
            // 获取e的值
            const num = e.target.value.trim()/1;
            // 如果输入的数值在正则表达式的范围内,则更新数据,否则使用旧的值
            if (goodsNumReg.test(num)){
                this.buyNum = num;
            }else{
                e.target.value = this.buyNum
            }
        },
        // 更新购买的数量(原生防抖)防抖是多次触发执行最后一个,节流是多次触发执行第一个
        upBuyNumByAntiShake(e){
            // 如果有定时器,先清除以前定时器
            if (this.timer){
                clearTimeout(this.timer);
            }
            // 声明一个单次定时器,1秒延迟后执行回调函数
            this.timer = setTimeout(()=>{
                // 获取input输入框的数值
                const num = e.target.value.trim() / 1;
                if (goodsNumReg.test(num)) {
                    this.buyNum = num;
                } else {
                    e.target.value = this.buyNum;
                }
            },1000)
        },
        // 使用第三方lodash实现防抖
        upBuyNumByLodash: debounce(function (e) {
            const num = e.target.value.trim() / 1;
            if (goodsNumReg.test(num)) {
                this.buyNum = num;
            } else {
                e.target.value = this.buyNum;
            }
        },1000),
        // 加减法函数
        changeBuyNum(e){
            // 减法
            if(e.target.classList.contains("mins")){
                if(this.buyNum ===1 ) return;
                this.buyNum--;
            } else if (e.target.classList.contains("plus")) {
                if (this.buyNum === 200) return;
                this.buyNum++;
            }
        }
    },

lodash

防抖的原理:

js
封装防抖函数
思路:

声明一个定时器变量
当鼠标每次滑动都判断是否有定时器,如果有定时器,先清除以前定时器
如果没有定时器,则开一个定时器
在定时器里面调用要执行的函数

const box = document.querySelector('.box')
let i = 1

function mouseMove() {
    box.innerHTML = i++
}

function debounce(fn, t) {
    // 1.声明一个定时器变量
    let timer
    return function () {
        // 2.如果有定时器,先清除定时器
        if (timer) clearTimeout(timer)
        // 3.4.重新设置定时函数
        timer = setTimeout(fn, t)
    }
}

box.addEventListener('mousemove', debounce(mouseMove, 200))

防抖和节流的区别:

vue
防抖是多次触发执行最后一个,节流是多次触发执行第一个

防抖 => 回城
节流 => 技能冷却

使用lodash实现防抖:

js
下载:cnpm install lodash
引入:import {debounce} from "lodash"
使用:_.debounce(要执行的函数, 延后执行的时间)
<!-- 在使用时我已经将lodash的js文件下载到了本地 -->
<script src="../lodash.min.js"></script>
<script>
    const box = document.querySelector('.box')
	let i = 1
    function mouseMove() {
        box.innerHTML = i++
    }
	box.addEventListener('mousemove', _.debounce(mouseMove, 200))
</script>

节流的原理:

js
封装节流函数思路:

声明一个定时器变量
当鼠标每次滑动都判断是否有定时器,如果有定时器已经开启,则不做操作
如果没有定时器,则开一个定时器
定时器到达时间,清空定时器

const box = document.querySelector('.box')
    let i = 1

    function mouseMove() {
      box.innerHTML = i++
    }

    function debounce(fn, t) {
      // 1.声明一个空定时器变量
      let timer = null
      return function () {
        // 2.如果没有定时器,可以设置定时器
        if (!timer) {
          timer = setTimeout(function () {
            fn()
            // 4.冷却完,清空定时器
            timer = null
          }, t)
        }
        // 3.如果已经有定时器,不做操作
      }
    }
    box.addEventListener('mousemove', debounce(mouseMove, 3000))

使用lodash实现节流:

js
<!-- 在使用时我已经将lodash的js文件下载到了本地 -->
<script src="../lodash.min.js"></script>
<script>
    const box = document.querySelector('.box')
    let i = 1
    function mouseMove() {
        box.innerHTML = i++
    }
    box.addEventListener('mousemove', _.throttle(mouseMove, 3000))
</script>

lodash实现防抖:src->pages->Details->index.vue

vue
https://www.lodashjs.com/docs/lodash.debounce#_debouncefunc-wait0-options

加入购物车成功界面

  1. 搭建加入购物车的路由:src->pages->AddCartSuccess->index.vue
vue
<template lang="">
    <div>
        <!-- 商品完成添加到购物车 -->
        <div class="cart-complete-wrap">
            <div class="cart-complete">
                <h3>
                    <i class="iconfont icon-success"></i>商品已成功加入购物车!
                </h3>
                <div class="goods">
                    <div class="left-good">
                        <div class="left-pic"><img src="../../assets/images/gocart.jpg"></div>
                        <div class="right-info">
                            <p class="title">美的(Midea)电饭煲WFZ5099IH IH电磁加热 1250W大火力 钛金釜5L电饭锅</p>
                            <p class="attr">颜色:WFZ5099IH/5L钛金釜内胆 数量:1</p>
                        </div>
                    </div>
                    <div class="right-gocart">
                        <a href="#" class="sui-btn btn-xlarge">查看商品详情</a>
                        <a href="cart.html" class="sui-btn btn-xlarge btn-danger " target="_blank">去购物车结算 &gt; </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name: "AddCartSuccess"
}
</script>
<style lang="less" scoped>
    ...
</style>
  1. 添加加入购物车的路由:src->router->index.js
js
import AddCartSuccess from '@/pages/AddCartSuccess';
...
    // 加入购物车的路由
    {
        path: "/addCartSuccess",
        component: AddCartSuccess,
    }
...
  1. 修改商品页跳转到加入购物车:src->pages->Details->index.vue
vue
<template lang="">
	...
	<div class="add">
        <a @click.prevent="addCart"  href="###" target="_blank">加入购物车</a>
    </div>
	...
</template>
<script>
methods: {
    // 加入购物车
    addCart(){
        this.$router.push("/addCartSuccess");
    }
}
</script>

切换商品配置

  1. 在数据仓库添加 mutations 用于更新商品的配置 src->store->product->index.js
js
// 商品信息
productInfo:{
    // 商品详情
    skuInfo: {
        // 定义缩略图列表,防止出现undefined 报错
        skuImageList: [],
            // 定义商品属性列表,防止出现undefined 
            spuSaleAttrList:[],
    }
}
// 修改productInfo中的配置信息,参数是 商品的颜色ID和版本ID
// 定义mutations
const mutations = {
    // 修改productInfo中的配置信息,参数是 商品的颜色ID和版本ID
    UP_ATTR_LIST_BY_ID(state,{a1Id,a2Id}){
        // 找到一级信息 颜色或者版本
        const info = state.productInfo.spuSaleAttrList.find(v => v.id === a1Id);
        
        if (info){
            // 找到二级中spuSaleAttrValueList的isChecked标记是1的
            const spuSaleAttrValue1 = info.spuSaleAttrValueList.find(v=>v.isChecked === '1');
            // 把之前的isChecked标记更改为0
            spuSaleAttrValue1.isChecked = "0";
            // // 更改二级中选中的spuSaleAttrValueList的isChecked标记
            const spuSaleAttrValue2 = info.spuSaleAttrValueList.find(v=>v.id === a2Id);
            // // 如果当前值为1,说明你点击的是已经选中的配置
            if (spuSaleAttrValue2.isChecked === "1") return;
            spuSaleAttrValue2.isChecked = "1";
        }
    },
...
}
  1. 修改详情页面中的:src->pages->Detail->index.vue
vue
<template lang="">
    <div>
        <div class="chooseArea">
            <div class="choosed"></div>
            <dl v-for="item in spuSaleAttrList" :key="item.id">
                <dt class="title">选择{{item.saleAttrName}}</dt>
                <dd changepirce="0" 
                    :class="{active:info.isChecked/1===1}"
                    v-for="info in item.spuSaleAttrValueList"
                    :key="info.id"
                    @click="$store.commit('product/UP_ATTR_LIST_BY_ID',{a1Id:item.id,a2Id:info.id})"
                    >{{info.saleAttrValueName}}
                </dd>
            </dl>
        </div>
    </div>
</template>
<script>
export default {
    
}
</script>
<style lang="">
    
</style>

购物车为空的页面

  1. 在购物车页面添加一个v-if判断:src->pages->Cart->index.vue
js
<div v-if="cartList.length>0" class="cart"></div>
<div v-else class="empty">
    <h3>购物车空空如也</h3>
	<img width="300px" src="../../assets/images/empty.gif" alt="">
</div>

呈现成功加入购物车信息

  1. 修改详情页面中的信息:src->pages->Detail->index.vue
js
...
<div class="add">
    <a @click.prevent="addCart"  href="###" target="_blank">加入购物车</a>
</div>
...
methods:{
        // 加入购物车,并存储到localStore中
        addCart() {
            // 创建sessionStorage对象,并把对象转为json字符串
            sessionStorage.setItem("addCartInfo", JSON.stringify({
                // 商品的详情信息
                ...this.skuInfo,
                // 购买数量
                buyNum: this.buyNum,
                // 商品属性信息
                attrList: this.spuSaleAttrList,
                
            }));
            // 跳转到加入购物车成功页面
            this.$router.push("/addCartSuccess")
        },
  1. 修改加入购物车的页面信息:src->pages->AddCartSuccess->index.vue
vue
<template lang="">
    <div>
                <!-- 商品完成添加到购物车 -->
        <div class="cart-complete-wrap">
            <div class="cart-complete">
                <h3>
                    <i class="iconfont icon-success"></i>商品已成功加入购物车!
                </h3>
                <div class="goods">
                    <div class="left-good">
                        <div class="left-pic">
                            <img width="60" height="60" :src="addCartInfo.skuDefaultImg">
                        </div>
                        <div class="right-info">
                            <p class="title">{{addCartInfo.skuName}}</p>
                            <!-- <p class="attr">颜色:WFZ5099IH/5L钛金釜内胆 数量:1</p> -->
                            <p v-for="item in addCartInfo.attrList" :key="item.id" class="attr">
                                {{item.saleAttrName}}:{{ item.spuSaleAttrValueList.find(v=>v.isChecked==='1').saleAttrValueName }}
                            </p>
                            <p class="attr">数量:{{addCartInfo.buyNum}}</p>
                            <p class="attr">价格:{{addCartInfo.price}}</p>
                        </div>
                    </div>
                    <div class="right-gocart">
                        <a @click.prevent="$router.go(-1)" href="#" class="sui-btn btn-xlarge">查看商品详情</a>
                        <a href="cart.html" class="sui-btn btn-xlarge btn-danger " target="_blank">去购物车结算 &gt; </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

完成购物车界面功能

搭建购物车路由

  1. 新建购物车页面组件:src->pages->Cart->index.vue
vue
<template>
    <!-- 购物车列表 -->
	....
</template>

<script>
export default {
    name: "Cart"
}
</script>
  1. 添加购物车页面的路由
js
    {
		path:"/cart",
		component:Cart,
		meta:{
			isTypeNav: true
		}
	}
  1. 在头部组件中添加购物车的路由
vue
<template>
   <div class="typeList">
     <a>我的订单</a>
     <router-link to="/cart">我的购物车</router-link>
     <a>我的尚品汇</a>
     <a>尚品汇会员</a>
     <a>企业采购</a>
     <a>关注尚品汇</a>
     <a>合作招商</a>
     <a>商家后台</a>
    </div>
</template>
  1. 在成功添加购物车的页面增加跳转购物车页面的路由
vue
<template>
	<div class="right-gocart">
    	<a @click.prevent="$router.go(-1)" href="#" class="sui-btn btn-xlarge">查看商品详情</a>
    	<router-link to="/cart" class="sui-btn btn-xlarge btn-danger ">去购物车结算 &gt; </router-link>
    </div>
</template>

获取购物车的数据

  1. 封装接口,获取购物车中的数据:src->api->cart.js
js
import {sphRequest} from "@/request";
// 获取购物车列表:/api/cart/cartList  get
export const getCartList = ()=>sphRequest.get("/cart/cartList");
  1. 封装购物车的数据仓库:src->store->cart->index.js
js
import getCartList from "@/api/cart";

const state = {
    // 购物车列表
    cartList: []
}

const mutations = {
    // 更新购物车的方法
    SAVE_CART_LIST(state, cartList) {
        state.cartList = cartList;
    }
}

const actions = {
    // 获取购物车的api
    async getCartListAsync({ commit }) {
        // 获取后端购物车信息
        const res = await getCartList();
        commit("SAVE_CART_LIST", res.data);
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}
  1. 将购物车数据仓库引入模块:src->store->index.js
js
import Vue from 'vue';
import Vuex from 'vuex';
// 导入product模块
import product from "@/store/product/index.js";
import adv from '@/store/adv/index';
import todaysell from './todaysell';
import cart from '@/store/cart/index';

// 挂载
Vue.use(Vuex);
// 定义store对象
const store = new Vuex.Store({
    modules:{
        product,
        adv,
        todaysell,
        cart
    }
});
// 导出store对象
export default store;
  1. 购物车页面挂载完成后,触发发送axios请求:src->pages->Cart->index.vue
vue
<script>
export default {
    name: "Cart",
    mounted(){
        this.$store.dispatch("cart/getCartListAsync");
    }
}
</script>

提示:此时后端数据库中并没有收到数据,所以无法得到数据。

  1. 向后端提交数据,添加api接口:src->api->cart.js
js
// 提交购物车数据
const postAddToCart = (skuId, skuNum) => {
    return sphRequest.post(`/cart/addToCart/${skuId}/${skuNum}`);
}

// 暴漏数据
export {
    postAddToCart,
    getCartList
}
  1. 封装 提交购物车数据 store
js
import {getCartList,postAddToCart} from "@/api/cart";

async postAddToCartAsync(content,{skuId,skuNum}){
    const res = await postAddToCart(skuId,skuNum);
    console.log(res);
}
  1. 在商品详情页面:src->pages->Detail->index.vue 修改添加购物车的方法
js
// 加入购物车,并存储到localStore中
        addCart() {
            // 创建sessionStorage对象,并把对象转为json字符串
            sessionStorage.setItem("addCartInfo", JSON.stringify({
                // 商品的详情信息
                ...this.skuInfo,
                // 购买数量
                buyNum: this.buyNum,
                // 商品属性信息
                attrList: this.spuSaleAttrList,
                
            }));
            // 提交购物车的数据到后端,调用cart中的action中的postAddToCart
            this.$store.dispatch("cart/postAddToCartAsync",{
                // 商品的ID
                skuId: this.$route.params.id,
                // 商品的购买数量
                skuNum: this.buyNum
            })
            // 跳转到加入购物车成功页面
            this.$router.push("/addCartSuccess")
        },
  1. 指定唯一标识:使用UUID第三方模块

UUID模块

  1. 下载UUID模块
js
npm install uuid
  1. 封装为一个工具类:src->utils->auth.js
js
// 导入uuid模块
import { v4 as uuidV4 } from "uuid"

const getUserTempId = function () {
    // 定义一个临时用户ID,判断缓存中是否存在
    let userTempId = localStorage.getItem("userTempId");

    if (!userTempId) {
        // 创建一个UUID
        userTempId = uuidV4();
        // 存储到缓存中
        localStorage.setItem("userTempId", userTempId);
    }
    // 返回
    return userTempId;
}

// 暴漏数据
export {
    getUserTempId
}
  1. 在请求拦截器中增加请求头 src->sphRequest.js
js
import 
// 请求拦截
sphRequest.interceptors.request.use(config => {
	nprogress.start();// 开启进度条
	config.headers.userTempId = getUserTempId()
	return config;
});
  1. 优化获取购物车数据的请求:src->store->cart->index.js
js
const actions = {
    // 获取购物车的请求
    async getCartListAsync({ commit }) {
        // 获取后端购物车信息,解构出data
        const {data} = await getCartList();
        // 使用commit提交 SAVE_CART_LIST
        commit("SAVE_CART_LIST", data[0] ? data[0].cartInfoList : []);
    },
}

渲染购物车数据

  1. 在购物册页面:src->pages->Cart->index.vue
vue
<template lang="">
    <div>
        <div class="cart-body">
            <ul class="cart-list"
                v-for="item in cartList"
                :key="item.id">
                <li class="cart-list-con1">
                    <input type="checkbox" name="chk_list" :checked="item.isChecked===1">
                </li>
                <li class="cart-list-con2">
                    <img :src="item.imgUrl">
                    <div class="item-msg">{{item.skuName}}</div>
                </li>
                <li class="cart-list-con4">
                    <span class="price">{{item.skuPrice|currency(2,"¥")}}</span>
                </li>
                <li class="cart-list-con5">
                    <a href="javascript:void(0)" class="mins">-</a>
                    <input autocomplete="off" type="text" :value="item.skuNum" minnum="1" class="itxt">
                    <a href="javascript:void(0)" class="plus">+</a>
                </li>
                <li class="cart-list-con6">
                    <span class="sum">{{(item.skuNum*item.skuPrice) | currency(2,"¥")}}</span>
                </li>
                <li class="cart-list-con7">
                    <a href="#none" class="sindelet">删除</a>
                    <br>
                </li>
            </ul>
        </div>
    </div>
</template>

切换商品的选中状态

方式1

直接调用接口修改选中的状态,本地数据未更改:
解决方案一:修改完成后,重新调用获取购物车列表相关的接口。
  1. 修改购物车的api:src->api->cart.js
js
// 切换商品选中状态 /api/cart/checkCart/{skuID}/{isChecked}  get
// skuID:商品ID
// isChecked:商品选中状态 0代表取消选中 | 1代表选中

// 获取购物车选中状态数据 /api/cart/checkCart/{skuID}/{isChecked}  get
const getCartIsCheckedById = (skuID, isChecked) => {
    return sphRequest.get(`/cart/checkCart/${skuID}/${isChecked}`)
}
  1. 添加store数据仓库:src->store->cart->index.js
js
// 获取购物车选中状态请求
async getCartIsCheckedByIdAsync({ dispatch }, { skuID, isChecked }){
    // 调用接口
    const res = await getCartIsCheckedById(skuID, isChecked);
    if (res.code === 200) {
        // 重新获取购物车列表。
        dispatch("getCartListAsync");
    } else {
        alert("异常:" + res.message)
    }
}
  1. 在页面中调用,并发送请求:src->pages->Cart->index.vue
html
<li class="cart-list-con1">
    <input @change="$store.dispatch('cart/getCartIsCheckedByIdAsync',{
                    skuID:item.skuId,
                    isChecked:item.isChecked===1?0:1
                    })" type="checkbox" :checked="item.isChecked===1" name="chk_list">
</li>

方式2

js
调用接口修改完数据之后,直接通过mutation修改本地仓库中的数据状态
  1. 修改store,添加mutation修改本地数据状态:src->store->cart.js
js
 const mutations = {
    // 更新store中购物车选中状态信息
    UP_CART_LIST_ISCHECKED_BY_ID(state, { skuID, isChecked }){
        // 找到商品
        const info = state.cartList.find(v => v.skuId === skuID);
        // 如果商品存在,把isChecked状态传递给store
        if(info){
            info.isChecked = isChecked;
        }
            
    }
} 

// 获取购物车选中状态请求
    async getCartIsCheckedByIdAsync({ commit }, { skuID, isChecked }){
        // 调用接口
        const res = await getCartIsCheckedById(skuID, isChecked);
        if (res.code === 200) {
            // 重新获取购物车列表。
            commit("UP_CART_LIST_ISCHECKED_BY_ID", { skuID, isChecked });
        } else {
            alert("异常:" + res.message)
        }
    }

删除购物车中商品

  1. 定义删除购物车接口:src->api->cart.js
js
// 删除购物车的数据 /api/cart/deleteCart/{skuId} delete
const deleteCartListById = (skuId) => {
    return sphRequest.delete(`/cart/deleteCart/${skuId}`)
}
  1. 在store中调用接口:src->store->cart.js
js
const mutations = {
	// 根据商品ID删除购物车中的商品
	DELETE_CART_LIST_BY_ID(state,skuId){
		state.cartList = state.cartList.filter(v=>v.skuId !== skuId);
	}
};
const actions = {
	async deleteCartListByIdAsync({dispatch,commit},skuId){
		// 根据商品ID删除购物车信息
		await deleteCartListById(skuId);
		// 方案一:更新购物车列表
		// await dispatch("getCartListAsync");
		// 方案二:
		commit("DELETE_CART_LIST_BY_ID",skuId);
	}
}
  1. 在购物车页面中触发async请求:src->pages->Cart->index.vue
vue
<template>
	<li class="cart-list-con7">
    <a @click.prevent="$store.dispatch('cart/deleteCartListByIdAsync',item.skuId)" href="#none" class="sindelet">删除</a>
    <br>
    </li>
</template>

删除购物车中选中的商品

  1. 添加批量删除购物车中的商品的api:src->api->cart.js
js
// 批量删除购物车  /api/cart/batchDeleteCart  post
// 参数:skuIdList  数组  代表修改的商品id列表     请求体参数
export const deleteCartListBatch = (data)=>sphRequest.post(`/cart/batchDeleteCart`,data)
  1. 在数据仓库中调用:src->store->cart.js
js
async deleteCartListBatchAsync({dispatch,state}){
    if(window.confirm("您确定要删除选中的数据吗")){
        // console.log(state.cartList.filter(v=>v.isChecked===1).map(item=>item.skuId));
        await deleteCartListBatch(state.cartList.filter(v=>v.isChecked===1).map(item=>item.skuId));
        await dispatch("getCartListAsync");
    }

},
  1. 在购物车页面触发async请求:src->pages->Cart->index.vue
vue
<div class="option">
                <a href="#none" @click="$store.dispatch('cart/deleteCartListBatchAsync')">删除选中的商品</a>
            </div>

计算选中的商品的数量和总价

  1. 在store数据仓库中定义getters中的方法:src->store->cart->index.js
js
const getters = {
    getCountResult({cartList}){
        let checkedNum = 0;
        let checkedPrice = 0;
        // console.log("cartList", cartList);
        cartList.forEach(item=>{
            if(item.isChecked ===1){
                checkedNum++;
                checkedPrice+=item.skuPrice*item.skuNum
            }
        })
        return {
            checkedNum,
            checkedPrice
        }
    }
}
  1. 在购物车页面中渲染:src->pages->Cart->index.vue
vue
<template>
   <div class="money-box">
    <div class="chosed">已选择
        <span>{{getCountResult.checkedNum}}</span>件商品</div>
    <div class="sumprice">
        <em>总价(不含运费) :</em>
        <i class="summoney">{{getCountResult.checkedPrice | currency(2,"¥")}}</i>
    </div>
    <div class="sumbtn">
        <a class="sum-btn" href="###" target="_blank">结算</a>
    </div>
    </div>
</template>

购物车中的数量加减

方式1

  1. 修改购物车页面中:src->pages->Cart->index.vue
vue
<template lang="">
    <div>
        <li class="cart-list-con5">
            <a href="javascript:void(0)" 
                @click.prevent="item.skuNum>1?item.skuNum--:1"
                :class="['mins']">-</a>
            <input 
                autocomplete="off" 
                type="text" 
                :value="item.skuNum" 
                minnum="1" 
                
                class="itxt">
            <a href="javascript:void(0)" 
                @click.prevent="item.skuNum<200?item.skuNum++:200"
                :class="['plus']">+</a>
        </li>
    </div>
</template>

方式2

  1. 添加 购物车商品数量的加减方法:src->pages->Cart->index.vue
vue
<template lang="">
    <div>
        <li class="cart-list-con5">
            <a href="javascript:void(0)" 
                @click.prevent="upBuyNum(item.skuId,item.skuNum,-1)"
                :class="{'mins':true,'disabled':item.skuNum===1}">-</a>
            <input 
                autocomplete="off" 
                type="text" 
                :value="item.skuNum" 
                minnum="1" 
                
                class="itxt">
            <a href="javascript:void(0)" 
                @click.prevent="upBuyNum(item.skuId,item.skuNum,1)"
                :class="{'plus':true,'disabled':item.skuNum===200}">+</a>
        </li>
    </div>
</template>
<script>
        methods:{
        // 购物车商品的加减
        async upBuyNum(skuId,skuNum,flag){
            // 判断边界问题
            const num = skuNum + flag;
            
            if (num < 1 || num > 200){
                return
            }else{
                // 调用异步请求
                await this.$store.dispatch("cart/postAddToCartAsync", {
                    skuId,
                    // 根据后端的接口说明,每次都是在上一次的基础上进行添加和删除
                    skuNum: flag
                });
                // 更新本地数据
                await this.$store.commit("cart/UP_CART_SKU_NUM", { 
                    skuId,
                    num
                })
            }
        },
        // 输入框修改商品的数量
        async changeBuyNum(e,skuId,skuNum){
            // 获取输入的数字
            const buyNum = e.target.value.trim()/1;
            // 使用正则判断是否合法
            if (goodsNumReg.test(buyNum)){
                console.log(buyNum);
                // 调用异步请求
                await this.$store.dispatch("cart/postAddToCartAsync", {
                    skuId,
                    // 根据后端的接口说明,每次都是在上一次的基础上进行添加和删除
                    skuNum: buyNum-skuNum,
                });
                // 刷新页面数据
                this.$store.commit("cart/UP_CART_SKU_NUM", {
                    skuId,
                    num:buyNum
                })
            }
        }
    },
</script>

防抖和节流优化

输入框防抖

  1. 在购物车页面修改:src->pages->Cart->index.vue
vue
<template lang="">
    <div>
        
    </div>
</template>
<script>
import { goodsNumReg } from '@/utils/reg';
import { debounce } from "lodash";    
export default {
    // 输入框修改商品的数量(使用debounce防抖)
    inputBuyNum: debounce(async function (e, skuId, skuNum){
        // 获取输入的数字
        const buyNum = e.target.value.trim() / 1;
        // skuNum:是修改前的数据
        if (goodsNumReg.test(buyNum)) {
            console.log(buyNum);
            // 调用异步请求
            await this.$store.dispatch("cart/postAddToCartAsync", {
                skuId,
                // 根据后端的接口说明,每次都是在上一次的基础上进行添加和删除
                skuNum: buyNum - skuNum,
            });
            // 刷新页面数据
            this.$store.commit("cart/UP_CART_SKU_NUM", {
                skuId,
                num: buyNum
            })
        }else{
            // 如果不符合正则表达式,把输入框的内容更改为原来的数值
            e.target.value = skuNum;
        }
    },1000)
}
</script>

加减号节流处理

  1. 在购物车页面修改:src->pages->Cart->index.vue
vue
<template lang="">
    <div>
        
    </div>
</template>
<script>
import { goodsNumReg } from '@/utils/reg';
import { debounce } from "lodash";    
export default {
    	// 购物车商品的加减(使用节流)
        async upBuyNumByOrificing(){
            // 技能未冷却,返回
            if (!this.isReaday){
                return;
            }
            // 判断边界问题
            const num = skuNum + flag;
            // 触发技能,技能冷却
            this.isReaday = false;
            if (num < 1 || num > 200) {
                return
            } else {
                // 调用异步请求
                await this.$store.dispatch("cart/postAddToCartAsync", {
                    skuId,
                    // 根据后端的接口说明,每次都是在上一次的基础上进行添加和删除
                    skuNum: flag
                })
                // 更新本地数据
                this.$store.commit("cart/UP_CART_SKU_NUM", {
                    skuId,
                    num
                })
            }
            // 冷却结束
            this.isReaday = true;
        },
}
</script>

搜索页面中的加入购物车

  1. 修改搜索页面中的:src->pages->Search->index.vue
vue
<template lang="">
    <div>
        
    </div>
</template>
<script>
import {mapState } from "vuex";
export default {
    methods:{
        // 加入购物车,并存储到localStore中
        async addCart(skuId) {
            // 获取商品的信息,发送获取商品详情的请求,这样页面的store中就会有商品的信息了
            await this.$store.dispatch("product/getProductInfoByIdAsync", skuId);
            // 创建sessionStorage对象,并把对象转为json字符串
            sessionStorage.setItem("addCartInfo", JSON.stringify({
                // 购买数量
                buyNum: 1,
                // 商品的详情信息
                ...this.skuInfo,
                // 商品属性信息
                attrList: this.spuSaleAttrList,
            }));
            // 提交购物车的数据到后端,调用cart中的action中的postAddToCart
            this.$store.dispatch("cart/postAddToCartAsync", {
                // 商品的ID
                skuId: skuId,
                // 商品的购买数量
                skuNum: 1
            })
            // 跳转到加入购物车成功页面
            this.$router.push("/addCartSuccess")
        },
    }
}
</script>
<style lang="">
    
</style>

完成购物车页面全选功能

js
1. 创建 getters 计算属性 产生全选的功能
2. 创建action,用于切换全选
  1. 添加 批量勾选的接口:src->api->cart.js
js
// 批量勾选购物车的商品 /api/cart/batchCheckCart/{isChecked}  post
// 参数:isChecked:是否选中,skuIdList,商品的列表信息
const postBatchCheckCart = (isChecked, skuIdList) => {
    return sphRequest.post(`/cart/batchCheckCart/${isChecked}`, skuIdList)
}
  1. 添加 获取购物车商品的勾选状态:src->store->cart.js中创建getters
js
// 获取购物车商品的勾选状态 { cartList } 从state中解构出 cartList
    getCartIsChecked({ cartList }){
        // 判断购物车中的商品是否都已经勾选
        return cartList.every(v=>v.isChecked ===1);
    }
  1. 添加 切换购物车商品的全选请求:src->store->cart.js中创建actions
js
// 切换购物车商品的全选请求
    async postBatchCheckCartAsync({ getters, state, dispatch }){
        // isChecked:要切换的状态,如果商品全部勾选,则返回0,否则则返回1==>相当于取反
        const isChecked = getters.getCartIsChecked?0:1;
        // 把购物车商品中未勾选的商品勾选:
        // 先过滤出未勾选的商品,然后把未勾选的商品重新组成一个数组(由商品Id组成的数组)
        const skuIdList = state.cartList.filter(v => v.isChecked === (getters.getCartIsChecked ? 1 : 0)).map(v => v.skuId)
        // 调用接口 提交批量勾选请求
        await postBatchCheckCart(isChecked, skuIdList);
        // 调用接口 刷新购物车商品信息
        await dispatch("getCartListAsync");
    },
  1. 添加 购物车商品页面全选触发开关:src->pages->cart->index.vue
vue
<template lang="">
    <div>
        <div class="select-all">
            <input 
                class="chooseAll"
                @change="$store.dispatch('cart/postBatchCheckCartAsync')" 
                :checked="getCartIsChecked"
                type="checkbox">
            <span>全选</span>
        </div>
    </div>
</template>