点击 加入购物车 的时候,先发请求,把数据存储到服务器,然后再进行路由跳转
// src/api/index.js
// 将产品添加到购物车中(或者 更新某一个产品个数)
// /api/cart/addToCart/{ skuId }/{ skuNum } POST 带参数
export const reqAddOrUpdateShopCart = (skuId,skuNum)=>{
return requests({url:`/cart/addToCart/${skuId}/${skuNum}`,method:'POST'})
}
派发actions,发请求
// src / pages / detail /index.vue
<div class="add">
<a @click="addShopcar">加入购物车a>
div>
// 加入购物车的回调函数
addShopcar() {
// 1. 发请求--将产品加入到数据库(通知服务器)
// 服务器存储成功----进行路由跳转
// 失败,给用户提示
this.$store.dispatch( "detail/addOrUpdateShopCart",{skuId:this.$route.params.skuId,skuNum:this.skuNum});
},
加入购物车以后(发请求),前台将参数带给服务器
服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功
⚠ !!!因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据
将参数带给服务器
const actions = {
// 将产品添加到购物车中
async addOrUpdateShopCart({commit},{skuId,skuNum}){
// 加入购物车返回的结果
let result = await reqAddOrUpdateShopCart(skuId,skuNum);
console.log('购物车',result);
// 加入购物车以后(发请求),前台将参数带给服务器
// 服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功
// 因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据
},
};
async
:只要有async返回的就是Promise,Promise返回的不是成功就是失败
发请求–将产品加入到数据库(通知服务器)
服务器存储成功----进行路由跳转
服务器存储失败------给用户提示
// src/pages/detail/index.vue
// 加入购物车的回调函数
async addShopcar() {
// 1. 发请求--将产品加入到数据库(通知服务器)
// 服务器存储成功----进行路由跳转
// 失败------给用户提示
try {
await this.$store.dispatch("detail/addOrUpdateShopCart", {skuId: this.$route.params.skuId,skuNum: this.skuNum,});
// 成功了进行路由跳转
.....
} catch (error) {
alert(error.message);
}
},
this.$store.dispatch("detail/addOrUpdateShopCart", {skuId: this.$route.params.skuId,skuNum: this.skuNum,});
表示调用了addOrUpdateShopCart
这个函数,调用这个函数,这个函数有async,说明这个函数的返回值是Promise函数await返回的是promise成功的值,但是我们要有成功做什么以及失败做什么…如果await的promise失败了,就会抛出异常,我们需要通过try…catch捕获处理
所以在detail.vue中,给 加入购物车的回调函数加上 async
// src/store/detail/index.js
// 将产品添加到购物车中
async addOrUpdateShopCart({ commit }, { skuId, skuNum }) {
// 加入购物车返回的结果
// 加入购物车以后(发请求),前台将参数带给服务器
// 服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功
// 因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据
let result = await reqAddOrUpdateShopCart(skuId, skuNum);
// 当前的这个函数,如果执行,返回promise
// 代表服务器加入购物车成功
if(result.code==200){
return 'ok'; // 返回的只要是非空字符串就是成功
}else{
// 代表加入购物车失败
return Promise.reject(new Error('false'));
}
},
注意:路由不是组件!!!??????❓
路由组件通常存放在
pages
文件夹,一般组件通常存放在components
文件夹。使用组件的步骤:创建-注册-引用-使用
创建路由,写到专门放路由的文件夹下
编写路由配置项:src/router/index.js
// 配置路由的地方
import Vue from 'vue';
import VueRouter from 'vue-router';
// 使用插件
Vue.use(VueRouter);
// 引入路由组件
import AddCartSuccess from '../pages/AddCartSuccess'
// 先把VueRouter原型对象的push,先保存一份
const originalPush = VueRouter.prototype.push
const originalReplace = VueRouter.prototype.replace
// 重写push | replace
// 参数:告诉原来的push方法,你往哪里跳转(传递哪些参数)
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function replace(location) {
return originalReplace.call(this, location).catch(err => err)
}
// 配置路由
export default new VueRouter({
// 配置路由
routes: [
...
{
name: 'addcartsuccess',
path: '/addcartsuccess',
component: AddCartSuccess,
meta: { showFooter: true }
},
// 重定向:在项目跑起来的时候,访问/,立马让他定向到首页!!!
{
path: '*',
redirect: '/home',
}
],
// 控制滚动条的滚动行为
scrollBehavior(to, from, savedPosition) {
// return 期望滚动到哪个的位置
return { y: 0 }; // 始终滚动到顶部
}
})
路由传参的话数据过多,在skuInfo里面,是个对象,以及还要带参数skuNum,地址栏会有点乱
所以这里我们只带skuNum参数传过去,其余复杂数据用会话存储—不持久化,会话结束数据消失
浏览器存储功能:HTML5中新增的,分为本地存储和会话存储
本地存储:持久化的,具有上限-----5M
会话存储:不是持久化的(浏览器关闭等),
// 加入购物车的回调函数
async addShopcar() {
// 1. 发请求--将产品加入到数据库(通知服务器)
// 服务器存储成功----进行路由跳转
// 失败------给用户提示
try {
await this.$store.dispatch("detail/addOrUpdateShopCart", {
skuId: this.$route.params.skuId,
skuNum: this.skuNum,
});
// 成功了进行路由跳转,并将产品的信息带给下一级的路由组件
// 会话存储 | 本地存储,一般存储的是字符串,所以将对象转换为字符串
sessionStorage.setItem('SKUINFO',JSON.stringify(this.skuInfo))
this.$router.push({
name: "addcartsuccess",
query:{skuNum:this.skuNum},
});
} catch (error) {
alert(error.message);
}
},
本地存储 里面只能存储字符串格式 ,因此需要把对象转换为字符串
JSON.stringify()
获取本地存储数据,需要把里面的字符串转换为对象格式
JSON.parse()
我们才能使用里面的数据。
获取本地存储数据
<div class="left-good">
<div class="left-pic">
<img :src="skuInfo.skuDefaultImg" />
div>
<div class="right-info">
<p class="title">{{ skuInfo.skuName }}p>
<p class="attr">
<span v-for="attrName in skuInfo.skuSaleAttrValueList" :key="attrName.id">{{ attrName.saleAttrName }} {{attrName.saleAttrValueName}} span>
<span>数量:{{$route.query.skuNum}}span>
p>
div>
div>
<div class="right-gocart">
跳转到detail商品详情页,携带参数
<div class="right-gocart">
<router-link :to="`/detail/${skuInfo.id}`" class="sui-btn btn-xlarge">查看商品详情router-link>
<a href="javascript:">去购物车结算 > a>
div>
跳转到购物车页面ShopCart
image-20220810195327300
引入和配置路由
// 配置路由的地方
import Vue from 'vue';
import VueRouter from 'vue-router';
// 使用插件
Vue.use(VueRouter);
// 引入路由组件
import ShopCart from '../pages/ShopCart'
// 先把VueRouter原型对象的push,先保存一份
const originalPush = VueRouter.prototype.push
const originalReplace = VueRouter.prototype.replace
// 重写push | replace
// 参数:告诉原来的push方法,你往哪里跳转(传递哪些参数)
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function replace(location) {
return originalReplace.call(this, location).catch(err => err)
}
// 配置路由
export default new VueRouter({
// 配置路由
routes: [
{
name: 'shopcart',
path: '/shopcart',
component: ShopCart,
meta: { showFooter: true },
},
// 重定向:在项目跑起来的时候,访问/,立马让他定向到首页!!!
{
path: '*',
redirect: '/home',
}
],
// 控制滚动条的滚动行为
scrollBehavior(to, from, savedPosition) {
// return 期望滚动到哪个的位置
return { y: 0 }; // 始终滚动到顶部
}
})
路由跳转
查看商品详情
去购物车结算 >
/api/cart/cartList GET 无参数
// src/api/index.js
// 获取购物车列表数据 /api/cart/cartList GET 无参数
export const reqCartList = ()=>{
return requests({url:'/cart/cartList',method:'GET'})
}
// src/store/shopcart/index.js
import { reqCartList } from '@/api/index'
const state = {};
const mutations = {};
const actions = {};
const getters = {};
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
// src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
// 需要使用插件
Vue.use(Vuex);
// 引入小仓库
import home from './home'
import search from './search'
import detail from './detail'
import shopcart from './shopcart';
// 对外暴露Store类的一个实例
export default new Vuex.Store({
// 实现vuex仓库模块式开发存储数据
modules:{
home,
search,
detail,
shopcart
}
})
vuex三连环
const actions = {
// 获取购物车列表的数据
async getCartList({ commit }) {
let result = await reqCartList();
console.log('购物车列表',result);
},
};
export default {
name: 'ShopCart',
mounted(){
// 获取服务器数据
this.getData();
},
methods:{
// 获取个人购物车数据
getData(){
this.$store.dispatch('shopcart/getCartList');
}
}
}
注意:发请求的时候,获取不到你购物车里的数据,因为这里不知道购物车获取谁的数据,需要给用户加一个身份!所以需要 UUID临时游客身份
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YEtvGoZp-1662259079858)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808200759898.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ACdKJbHu-1662259079859)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808201000762.png)]
开始真正的vuex三连环!!
这个是shopcart仓库里面的数据,有点复杂,所以我们要简化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Of4Utzy-1662259079860)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808201439581.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4i69LqhO-1662259079860)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808202719439.png)]
import { reqCartList } from '@/api/index'
const state = {
cartList:[],
};
const mutations = {
GETCARTLIST(state, cartList) {
state.cartList = cartList;
}
};
const actions = {
// 获取购物车列表的数据
async getCartList({ commit }) {
let result = await reqCartList();
if (result.code == 200) {
commit('GETCARTLIST', result.data); // result.data 是个数组
}
},
};
const getters = {
cartList(state){
// state.cartList[0] 如果没有返回,至少是个数组
return state.cartList[0]|| [];
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
现在仓库里面有了数据
...mapGetters("shopcart", ["cartList"])
, 组件开始获取数据
遍历用every
开始渲染数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i26xVFfG-1662259079861)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808212414091.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18SJZW75-1662259079862)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808212440861.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EWbSh8pV-1662259079863)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808212503712.png)]
在点击 加入购物车 的时候,告诉服务器你是谁
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGm7EbdK-1662259079863)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220808192559148.png)]
utils :放一些常用的功能模块,比如正则,uuid
将游客身份用会话存储(sessionStorage)保存,放到detail仓库里
uuid是一个随机的字符串,且每次执行不能发生变化,且持久存储,
所以每次调用getUUID函数的时候,先从本地存储获取uuid,看会话存储是否有,
如果有的话就返回会话存储里面的uuid,
如果没有的话,就生成uuid
// src/utils/uuid_token.js
import {v4 as uuidv4} from 'uuid'
// 要生成一个随机的字符串,且每次执行不能发生变化,游客身份持久存储
export const getUUID = ()=>{
// 先从会话存储获取uuid,看一下本地存储是否有
let uuid_token = sessionStorage.getItem('UUIDTOKEN');
// 如果没有,我就生成UUID
if(!uuid_token){
uuid_token=uuidv4();
// 会话存储 存储一次
sessionStorage.setItem('UUIDTOKEN',uuid_token);
}
// 切记要有返回值!
return uuid_token;
}
在detail仓库里面存储uuid
// src/store/detail/index.js
// 封装游客身份模块uuid---生成一个随机的字符串(不能再变了)
import {getUUID} from '@/utils/uuid_token'
const state = {
goodsInfo: {}, // 看api文档,result.data返回的是一个对象
// 游客临时身份
uuid_token:getUUID(),
};
现在游客身份在仓库里,我们要把数据带给服务器,可以利用请求头把数据带给服务器
找到请求拦截器,在请求拦截器捞到仓库里的数据
// src/api/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;
})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K7aqRROw-1662259079864)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220809152304140.png)]
点击 + 或 - 或 修改input框里的数字,input框里发生变化
问:这个时候向服务器发请求吗?
发请求,如果不发请求的话,服务器里的数据还是原来的,那么该页面的关于数量的数据和原来一样,
-----------所以我们每当修改的时候,就要发请求给服务器,然后再从服务器捞到数据,进行渲染页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WV58t3dV-1662259079865)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220809191528932.png)]
这个之前写过api(在将产品添加到购物车那里,detail详情页,也有仓库了)所以我们可以把数据存到detail仓库,就现在直接派发action就行了,然后再重新捞数据渲染
这里的skuNum是 现在状态的数字 与 起始状态的数字 的差值。比如:现在商品数量是5,我们要买12,这个skuNum是12-5 = 7
找到产品数量的结构位置
-
-
+
这三个节点 要派发同一个action,也就是说这三个节点调用同一个回调函数
问:但是如何判断这三个节点?
通过传参。三个不同的参数,用形参接收,来区分这三个节点
要传三个参数
第一个参数type 是用来区分它们三个节点
第二个参数是disNum,他们的变化量,+号是1,-号是-1,input框暂定不是变化量,是修改后的值
第三个参数是cart 当前他们点击的产品的信息cart,然后得知他们的id,因为要发请求需要skuID
-
-
+
先写 + 号 和 - 号
加号:直接带给服务器变化的量
减号:判断产品的当前数量是否大于1,大于1才能减,传递给服务器-1
然后就是派发action发请求,发给服务器后再 捞数据 渲染页面
// 购物车里 修改某一个产品的个数
handler(type, disNum, cart) {
//disNum 代表 现在状态的数字 与 起始状态的数字 的差值
// 目前disNum 形参: + 号变化量(1),- 号 变化量 (-1),input 最终的量(并不是变化量)
// 向服务器发请求,修改数量
switch (type) {
// 加号
case "plus": {
// 带给服务器变化的量
disNum = 1;
break;
}
// 减号
case "mins": {
// 判断产品的数量是否大于1,大于1才能减,传递给服务器-1
if (cart.skuNum > 1) {
disNum = -1;
} else {
// 产品的个数小于等于1,传递给服务器的个数为 0
disNum = 0;
}
break;
}
}
// 派发action 发请求
try {
// 代表的是修改购物车中产品数量修改成功
await this.$store.dispatch("detail/addOrUpdateShopCart", {
skuId: cart.skuId,
skuNum: disNum,
});
// 再一次获取服务器的最新数据进行展示
this.getData();
} catch (error) {
// 修改失败
alert(error.message)
}
},
解决 input 框里面输入数字
如果input框里面输入的不是数字,或者小于1,则带给服务器的数字是0
如果输入的是小数,将你最终输入的取整,然后减去最初的数量,就是你要传的变化量disNum
// input框
case "change": {
// 如果input框里面输入的不是数字,或者小于1,则带给服务器的数字是0
if (isNaN(disNum) || disNum < 1) {
disNum = 0;
} else {
// 如果输入的是小数,将你最终输入的取整,然后减去最初的数量,就是你要传的变化量disNum
disNum = parseInt(disNum) - cart.skuNum;
}
break;
}
对修改购物车产品的数量 进行节流操作
当你刚到购物车页面的时候,快速点击 - 号,商品的数量会变成负数、
这是因为 用户操作太频繁,请求服务器跟不上--------------所以我们用到【节流】,限制用户的操作
// 原来写法
async handler(type, disNum, cart) {
//disNum 代表 现在状态的数字 与 起始状态的数字 的差值
// 目前disNum 形参: + 号变化量(1),- 号 变化量 (-1),input 最终的量(并不是变化量)
// 向服务器发请求,修改数量
switch (type) {
// 加号
case "plus": {
// 带给服务器变化的量
disNum = 1;
break;
}
// 减号
case "mins": {
// 判断产品的数量是否大于1,大于1才能减,传递给服务器-1
if (cart.skuNum > 1) {
disNum = -1;
} else {
// 产品的个数小于等于1,传递给服务器的个数为 0
disNum = 0;
}
break;
}
// input框
case "change": {
// 如果input框里面输入的不是数字,或者小于1,则带给服务器的数字是0
if (isNaN(disNum) || disNum < 1) {
disNum = 0;
} else {
// 如果输入的是小数,将你最终输入的取整,然后减去最初的数量,就是你要传的变化量disNum
disNum = parseInt(disNum) - cart.skuNum;
}
break;
}
}
// 派发action 发请求
try {
// 代表的是修改购物车中产品数量修改成功
await this.$store.dispatch("detail/addOrUpdateShopCart", {
skuId: cart.skuId,
skuNum: disNum,
});
// 再一次获取服务器的最新数据进行展示
this.getData();
} catch (error) {
// 修改失败
alert(error.message);
}
},
引入节流
// 最好的引入方式:按需加载
import throttle from "lodash/throttle";
整理代码
// 购物车里 修改某一个产品的个数,使用【节流】
handler: throttle(async function (type, disNum, cart) {
// 原来代码
}, 500),
写api接口
// src/api/index.js
// 删除购物车商品数据 /api/cart/deleteCart/{skuId} DELETE 带参数skuId
export const reqDeleteCartById=(skuId)=>{
return requests({url:`/cart/deleteCart/${skuId}`,method:'DELETE'})
}
写仓库vuex,去购物车的仓库里写
这里就不用拿数据了,因为是删除数据!!!
const actions = {
// 删除购物车商品的数据
async deleteCartListBySkuId({ commit }, skuId) {
let result = await reqDeleteCartById(skuId);
if (result.code == 200) {
return 'ok'
} else {
return Promise.reject(new Error('删除购物车商品失败'))
}
}
};
点击 删除 的时候 派发action,需要传参,当前商品的skuId
-
删除
移到收藏
删除购物车商品的操作
如果删数据成功,则发请求显示新的数据,如果失败弹窗失败信息
// 删除购物车商品的操作
async deleteCartById(cart) {
// 如果删数据成功,则发请求显示新的数据,如果失败弹窗失败信息
try {
await this.$store.dispatch(
"shopcart/deleteCartListBySkuId",
cart.skuId
);
// 再次发请求显示新的数据
this.getData();
} catch (error) {
alert(error.message);
}
},
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zxapznmq-1662259079865)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220810173640178.png)]
每次修改完状态也是要向服务器发请求的
写api接口
// 切换商品的选中状态 /api/cart/checkCart/{skuId}/{isChecked} GET请求 带参数
export const reqUpdateCheckedById = (skuId, isChecked) => {
return requests({ url: `/cart/checkCart/${skuId}/${isChecked}`, method: 'GET' })
}
vuex----派发actions 与 仓库捞到数据 (不返回数据)
多个参数的话,多个参数用
{}
对象包裹!!注意!不能只传个参数 cart ,因为isChecked不变的,它获取的是后台的数据,一直是1
可以用
event.target.checked
获取当前元素的checked属性
// src/pages/ShopCart/index.vue
-
.....
// 修改购物车是否勾选状态
async updateChecked(cart, event) {
try {
let checked = event.target.checked ? "1" : "0"; // 注意,接口文档要的是string类型
await this.$store.dispatch("shopcart/updateCheckedById", {
skuId: cart.skuId,
isChecked: checked,
});
this.getData();
} catch (error) {
alert(err.message)
}
},
const actions = {
// 修改产品的勾选状态
async updateCheckedById({ commit }, { skuId, isChecked }) {
let result = await reqUpdateCheckedById(skuId, isChecked);
if (result.code == 200) {
return 'ok'
} else {
return Promise.reject(new Error('修改商品的勾选状态失败咯'))
}
}
}
注意:没有一次删除很多产品的接口,但是有通过ID可以删除产品的接口【一次只能删一个】
------所以我们可以多调用几次接口
给 删除所选商品 绑定点击事件
删除选中的商品
// 删除所选中的全部商品
// 这个回调函数我们没办法搜集到一些有用的数据
deleteAllCheckedCart(){
// 派发actions
this.$store.dispatch('shopcart/deleteAllCheckedCart')
},
当点击 删除选中的商品,我们就要派发actions,执行shopcart里面的deleteAllCheckedCart回调函数来删除
我们想多调用几次删除商品的接口,这样就可以删除所选的全部商品了
actions里面的函数都有两个参数,第一个是
context
,它相当于一个小仓库,里面有 commit【提交mutations修改state】 getters【计算属性】 dispatch【派发actions】 state【当前仓库数据】
调用删除商品的接口需要两个参数,要有dispatch可以派发actions才能调用,然后就是商品的ID
所以我们的deleteAllCheckedCart
可以从context
里面拿到两个参数,分别是dispatch和getters
getters.cartList.cartInfoList; // 这就是购物车里的所有产品
我们可以用
forEach
来遍历购物车里面的所有商品,但是我们要删除的是勾选上的商品,所以可以用IF来进行判断,如果商品的isChecked为1,说明勾选上了,我们就让这个商品调用删除函数我们要知道所选商品是否删除成功,可以用
Promise.all([p1,p2,p3])
p1 | p2 | p3 每一个都是promise对象,如果有一个promise失败,都失败,如果都成功,返回成功
让我们勾选上的商品都为promise,然后将每一次返回的promise添加到数组PromiseAll当中,最后
Promise.all(PromiseAll)
看你删除 勾选的全部商品成功还是失败
const actions={
.....
// 删除勾选的全部产品
deleteAllCheckedCart({ dispatch, getters }) {
// 要拿到context里面的dispatth和getters,因为要派发action调用删除购物车的函数 ,以及需要数据
// getters.cartList.cartInfoList; // 这就是购物车里的所有产品
let PromiseAll = [];
getters.cartList.cartInfoList.forEach(item => {
// 购物车有多少产品,就调用多少 deleteCartListBySkuId 这个函数
// !!但是我们要删除的是勾选上的商品
let promise = item.isChecked == 1 ? dispatch('deleteCartListBySkuId', item.skuId) : '';
// 将每一次返回的promise添加到数组当中
PromiseAll.push(promise);
});
// Promise.all只要全部的商品都删除成功,返回结果就是成功
return Promise.all(PromiseAll); // 看你删除勾选的全部商品成功还是失败
}
}
最后我们在用try...catch
,如果成功,则再次发请求获取购物车列表,如果失败,报错
// 删除所选中的全部商品
// 这个回调函数我们没办法搜集到一些有用的数据
async deleteAllCheckedCart() {
try {
// 派发actions
await this.$store.dispatch("shopcart/deleteAllCheckedCart");
// 再次发请求获取购物车列表
this.getData();
} catch (error) {
alert(error.message)
}
},
},
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EOVCZLVM-1662259079866)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220811113304882.png)]
我们现在解决了 当上面的勾选框全都勾选上了,下面的全选按钮全都勾选上
但是没有解决 当下面全选按钮勾选上的时候,上面的也都要勾选上
1. 修改产品的勾选状态 这个请求 一次只能勾选一个,而我们是要全部产品勾选上,所以我们可以多发几次请求。
2. 当点击 【全选】的时候,派发一个actions,去调用一个函数【这个函数可以多次发请求修改产品的勾选状态】,这个函数 我们要执行【遍历上面所有产品,如果勾选框勾上了--不动,如果勾选框没勾上---发请求修改产品的勾选状态】
给【全选】绑定事件
<div class="select-all">
<input class="chooseAll" type="checkbox" :checked="isAllChecked" @change="updateAllCartChecked" />
<span>全选span>
div>
派发actions
问:需要传参数吗
答:需要,因为我们发请求的时候需要商品的ID和isChecked,而我们对商品的isChecked修改是根据 【全选】的checked来修改。如果全选的checked为1,那么商品的isChecked为1,否则就是0。所以我们需要拿到当前状态该【全选】的checked值
// 修改全部产品的勾选状态
updateAllCartChecked(event){
// console.log(event.target.checked); // 返回的是布尔值
let isChecked = event.target.checked ? "1" : "0"; // 我们发请求需要的是布尔值
// 派发actions
this.$store.dispatch('shopcart/updateAllCartIsChecked',isChecked)
}
vuex,多调用几次修改产品勾选状态的函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9iG0G9l-1662259079866)(D:\桌面\前端学习\12-VUE\尚品汇-前台项目\project_SPH\尚品汇开发笔记.assets\image-20220811115204649.png)]
我们拿state里面的数据
state.cartList.cartInfoList
里面才是我们购物车里商品的数据
// 修改全部商品的勾选状态
updateAllCartIsChecked({ dispatch, getters }, isChecked) {
let promiseAll = [];
// 遍历购物车里面的所有商品
getters.cartList.cartInfoList.forEach(item => {
// 向修改产品的勾选状态发请求,带两个参数,第二个参数是【全选】的勾选状态
// 目的:让购物车里面的商品勾选状态与全选一致
let promise = dispatch('updateCheckedById', { skuId: item.skuId, isChecked: isChecked });
promiseAll.push(promise); // 将每一次返回的promise添加到数组promiseAll当中
});
// 最终返回的结果 Promise.all只要全部的商品都修改成功,返回结果就是成功
return Promise.all(promiseAll);
},
最后我们用try...catch
,如果成功,则再次发请求获取购物车列表,如果失败,报错
// 修改全部商品的勾选状态
updateAllCartIsChecked({ dispatch, getters }, isChecked) {
let promiseAll = [];
// 遍历购物车里面的所有商品
getters.cartList.cartInfoList.forEach(item => {
// 向修改产品的勾选状态发请求,带两个参数,第二个参数是【全选】的勾选状态
// 目的:让购物车里面的商品勾选状态与全选一致
let promise = dispatch('updateCheckedById', { skuId: item.skuId, isChecked: isChecked });
promiseAll.push(promise); // 将每一次返回的promise添加到数组promiseAll当中
});
// 最终返回的结果 Promise.all只要全部的商品都修改成功,返回结果就是成功
return Promise.all(promiseAll);
},
解决小问题:当购物车里面商品没有的时候,全选框不可点击且不勾选上
cartInfoList.length > 0
当购物车商品数组长度>0才勾选上
:disabled="cartInfoList == 0"
当购物车商品数组长度=0,不能被点击
全选