购物车页面
购买数量加减操作
- 在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-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}$/
- 应用正则表达式:src->pages->Details->index.vue
js
import {goodsNumReg} from "@/utils/reg";
实现防抖
- 在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>
- 使用第三方实现防抖 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
加入购物车成功界面
- 搭建加入购物车的路由: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">去购物车结算 > </a>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "AddCartSuccess"
}
</script>
<style lang="less" scoped>
...
</style>
- 添加加入购物车的路由:src->router->index.js
js
import AddCartSuccess from '@/pages/AddCartSuccess';
...
// 加入购物车的路由
{
path: "/addCartSuccess",
component: AddCartSuccess,
}
...
- 修改商品页跳转到加入购物车: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>
切换商品配置
- 在数据仓库添加 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";
}
},
...
}
- 修改详情页面中的: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>
购物车为空的页面
- 在购物车页面添加一个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>
呈现成功加入购物车信息
- 修改详情页面中的信息: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")
},
- 修改加入购物车的页面信息: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">去购物车结算 > </a>
</div>
</div>
</div>
</div>
</div>
</template>
完成购物车界面功能
搭建购物车路由
- 新建购物车页面组件:src->pages->Cart->index.vue
vue
<template>
<!-- 购物车列表 -->
....
</template>
<script>
export default {
name: "Cart"
}
</script>
- 添加购物车页面的路由
js
{
path:"/cart",
component:Cart,
meta:{
isTypeNav: true
}
}
- 在头部组件中添加购物车的路由
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>
- 在成功添加购物车的页面增加跳转购物车页面的路由
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 ">去购物车结算 > </router-link>
</div>
</template>
获取购物车的数据
- 封装接口,获取购物车中的数据:src->api->cart.js
js
import {sphRequest} from "@/request";
// 获取购物车列表:/api/cart/cartList get
export const getCartList = ()=>sphRequest.get("/cart/cartList");
- 封装购物车的数据仓库: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
}
- 将购物车数据仓库引入模块: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;
- 购物车页面挂载完成后,触发发送axios请求:src->pages->Cart->index.vue
vue
<script>
export default {
name: "Cart",
mounted(){
this.$store.dispatch("cart/getCartListAsync");
}
}
</script>
提示:此时后端数据库中并没有收到数据,所以无法得到数据。
- 向后端提交数据,添加api接口:src->api->cart.js
js
// 提交购物车数据
const postAddToCart = (skuId, skuNum) => {
return sphRequest.post(`/cart/addToCart/${skuId}/${skuNum}`);
}
// 暴漏数据
export {
postAddToCart,
getCartList
}
- 封装 提交购物车数据 store
js
import {getCartList,postAddToCart} from "@/api/cart";
async postAddToCartAsync(content,{skuId,skuNum}){
const res = await postAddToCart(skuId,skuNum);
console.log(res);
}
- 在商品详情页面: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")
},
- 指定唯一标识:使用UUID第三方模块
UUID模块
- 下载UUID模块
js
npm install uuid
- 封装为一个工具类: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
}
- 在请求拦截器中增加请求头 src->sphRequest.js
js
import
// 请求拦截
sphRequest.interceptors.request.use(config => {
nprogress.start();// 开启进度条
config.headers.userTempId = getUserTempId()
return config;
});
- 优化获取购物车数据的请求: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 : []);
},
}
渲染购物车数据
- 在购物册页面: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
直接调用接口修改选中的状态,本地数据未更改:
解决方案一:修改完成后,重新调用获取购物车列表相关的接口。
- 修改购物车的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}`)
}
- 添加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)
}
}
- 在页面中调用,并发送请求: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修改本地仓库中的数据状态
- 修改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)
}
}
删除购物车中商品
- 定义删除购物车接口:src->api->cart.js
js
// 删除购物车的数据 /api/cart/deleteCart/{skuId} delete
const deleteCartListById = (skuId) => {
return sphRequest.delete(`/cart/deleteCart/${skuId}`)
}
- 在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);
}
}
- 在购物车页面中触发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>
删除购物车中选中的商品
- 添加批量删除购物车中的商品的api:src->api->cart.js
js
// 批量删除购物车 /api/cart/batchDeleteCart post
// 参数:skuIdList 数组 代表修改的商品id列表 请求体参数
export const deleteCartListBatch = (data)=>sphRequest.post(`/cart/batchDeleteCart`,data)
- 在数据仓库中调用: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");
}
},
- 在购物车页面触发async请求:src->pages->Cart->index.vue
vue
<div class="option">
<a href="#none" @click="$store.dispatch('cart/deleteCartListBatchAsync')">删除选中的商品</a>
</div>
计算选中的商品的数量和总价
- 在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
}
}
}
- 在购物车页面中渲染: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
- 修改购物车页面中: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
- 添加 购物车商品数量的加减方法: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>
防抖和节流优化
输入框防抖
- 在购物车页面修改: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>
加减号节流处理
- 在购物车页面修改: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>
搜索页面中的加入购物车
- 修改搜索页面中的: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,用于切换全选
- 添加 批量勾选的接口:src->api->cart.js
js
// 批量勾选购物车的商品 /api/cart/batchCheckCart/{isChecked} post
// 参数:isChecked:是否选中,skuIdList,商品的列表信息
const postBatchCheckCart = (isChecked, skuIdList) => {
return sphRequest.post(`/cart/batchCheckCart/${isChecked}`, skuIdList)
}
- 添加 获取购物车商品的勾选状态:src->store->cart.js中创建getters
js
// 获取购物车商品的勾选状态 { cartList } 从state中解构出 cartList
getCartIsChecked({ cartList }){
// 判断购物车中的商品是否都已经勾选
return cartList.every(v=>v.isChecked ===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");
},
- 添加 购物车商品页面全选触发开关: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>