当前位置: 首页 > news >正文

vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

在这里插入图片描述

文章目录

    • 29.加入购物车操作(难点)
      • 29.1加入购物车按钮
      • 29.2addCartSuce
      • 29.3购物车
        • 29.3.1 向服务器发送ajax请求,获取购物车数据
        • 29.3.2UUID临时游客身份
        • 29.3.3动态展示购物车
      • 29.4修改购物车产品的数量(需要发请求:参数理解)
      • 29.5删除某一产品
      • 29.6修改产品状态
      • 29.7删除全部选中的商品
      • 29.8全选操作
  • 本人其他相关文章链接

29.加入购物车操作(难点)

重难点说明

  1. 用户临时ID的处理

  2. 购物车数据的管理(复杂)

  3. 不使用v-model监控用户输入

  4. async / await / Promise.all() 的使用

思路:

  1. 加入购物车按钮

    • 路由跳转之前发请求

    • 成功路由跳转与参数传递

    • 失败提示失败信息

  2. addCartSuce

    • 查看详情
    • 查看购物车
  3. 购物车

    • 购物车静态组件-需要修改样式结构(删除第三项并调整css让各个项目对齐,比例为:15 35 10 17 10 13)
    • 向服务器发送ajax请求,获取购物车数据
    • UUID临时游客身份
    • 动态展示购物车
  4. 修改购物车产品的数量(需要发请求:参数理解)

  5. 删除某一产品

  6. 修改产品状态

  7. 删除全部选中的商品

  8. 全选操作

29.1加入购物车按钮

加入购物车按钮

  • 路由跳转之前发请求

  • 成功路由跳转与参数传递

  • 失败提示失败信息

修改代码:

src/pages/Detail/index.vue

<a href="javascript:" @click="addOrUpdateShopCar">加入购物车</a>methods: {//加入购物车async addOrUpdateShopCar() {//1:在点击加入购物车这个按钮的时候,做的第一件事情,将参数带给服务器(发请求),通知服务器加入购车的产品是谁//this.$store.dispatch('addOrUpdateShopCart'),说白了,它是在调用vuex仓库中的这个addOrUpdateShopCart函数。//2:你需要知道这次请求成功还是失败,如果成功进行路由跳转,如果失败,需要给用户提示try {//成功await this.$store.dispatch("addOrUpdateShopCar", {skuId: this.$route.params.skuId, skuNum: this.skuNum});//3:进行路由跳转//4:在路由跳转的时候还需要将产品的信息带给下一级的路由组件//一些简单的数据skuNum,通过query形式给路由组件传递过去//产品信息的数据【比较复杂:skuInfo】,通过会话存储(不持久化,会话结束数据在消失)//本地存储|会话存储,一般存储的是字符串sessionStorage.setItem("SKUINFO", JSON.stringify(this.skuInfo))this.$router.push({name: "addCartSuccess", query:{skuNum: this.skuNum}})} catch (error) {//失败alert(error.message);}}
}

src/api/index.js

//将产品添加到购物车中(获取更新某一个产品的个数)
// /api/cart/addToCart/{ skuId }/{ skuNum }  POST
export const addOrUpdateShopCar = (skuId, skuNum)=>requests({url:`/cart/addToCart/${skuId}/${skuNum}`, method:"post"});

src/store/detail/index.js

import {getGoodsInfo, addOrUpdateShopCar} from "@/api";const actions = {//加入购物车的||修改某一个产品的个数,注意一定要用解构方法解构形参对象,不能写成接收两个形参形式,那样会报错接口调不通async addOrUpdateShopCar(context, {skuId, skuNum}) {//发请求:前端带一些参数给服务器【需要存储这些数据】,存储成功了,没有给返回数据//不需要在三连环(仓库存储数据了)//注意:async函数执行返回的结果一定是一个promise【要么成功,要么失败】let response = await addOrUpdateShopCar(skuId, skuNum);if (response.code == 200) {//返回的是成功的标记return "OK";} else {//返回的是失败的标记return Promise.reject(new Error("fail"))}},
}

注意点1:

问题:加入购物车路由跳转跟普通的路由跳转不一样,不一样在哪里?

答案:因为加入购物车功能得先调接口保存加入购物车的数据,然后再跳转路由。而普通的路由跳转直接跳转并传参就行。

注意点2:

问题:点击购物车函数派发定义在详情组件中,但是加入购物车接口调用在仓库中,如何获取调用函数的结果呢?

答案:第一种方案在vuex的state中保存结果,第二种方案在详情组件中采用async+await修饰派发方法获取调用成功失败结果。

注意点3:

问题:如下代码vuex中执行ajax调用接口返回失败,为啥?

src/api/index.js

//将产品添加到购物车中(获取更新某一个产品的个数)
// /api/cart/addToCart/{ skuId }/{ skuNum }  POST
export const addOrUpdateShopCar = (skuId, skuNum)=>requests({url:`/cart/addToCart/${skuId}/${skuNum}`, method:"post"});

src/store/detail/index.js

 async addOrUpdateShopCar(context, skuId, skuNum) {let response = await addOrUpdateShopCar(skuId, skuNum);console.log("******response:", response)       }

报错如下:

在这里插入图片描述

答案:vuex中action定义的函数接收形参书写个数不对。

如果是一个参数可以写成:addOrUpdateShopCar(context, skuId)
但如果是传入多个参数则不能这样写:这是错误写法:addOrUpdateShopCar(context, skuId, skuNum)
正确写法是派发时传入一个对象通过解构方式获取属性值,正确写法:addOrUpdateShopCar(context, {skuId, skuNum})

注意点4:

问题:理解异步函数async和await的用法?

答案:

  1. async 函数
    1)函数的返回值为Promise对象
    2)Promise对象的结果由async函数执行的返回值决定
  2. await 表达式
    1)await右侧的表达式一般为promise对象, 但也可以是其它的值
    2)如果表达式是promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。
    3)如果表达式是其它值, 直接将此值作为await的返回值
  3. asyncawait基于promise的。使用async的函数将会始终返回一个 promise 对象。这一点很重要,要记住,可能是你遇到容易犯错的地方。
  4. 在使用await的时候我们只是暂停了函数,而非整段代码。
  5. async和await是非阻塞的
  6. 仍然可以使用 Promise,例如Promise.all().
  7. 注意
    1)await必须写在async函数中, 但async函数中可以没有await
    2)如果await的promise失败了, 就会抛出异常, 需要通过try…catch来捕获处理

29.2addCartSuce

重难点说明:区别使用sessionStorage与localStorage

addCartSuce

  • 查看详情
  • 查看购物车

效果如图

在这里插入图片描述

修改代码:

拷贝src/pages/AddCartSuccess文件夹

src/router/routes.js

import AddCartSuccess from '@/pages/AddCartSuccess'
import ShopCart from '@/pages/ShopCart'
{name: 'addCartSuccess',path: '/addCartSuccess',component: AddCartSuccess,meta:{"isShow": true}   //自定义元数据属性,判断Footer组件在底部是否显示
},
{name: 'shopCart',path: '/shopCart',component: ShopCart,meta:{"isShow": true}   //自定义元数据属性,判断Footer组件在底部是否显示
},

src/pages/AddCartSuccess/index.vue

<img :src="skuInfo.skuDefaultImg">
<p class="title">{{skuInfo.skuName}}</p>
<p class="attr">{{skuInfo.skuDesc}} 数量:{{$route.query.skuNum}}</p>
<router-link class="sui-btn btn-xlarge" :to="`/detail/${skuInfo.id}`">查看商品详情</router-link>
<router-link to="/shopCart">去购物车结算</router-link>computed: {skuInfo() {return JSON.parse(sessionStorage.getItem("SKUINFO"))}
}

注意点1:

问题:点击加入购物车按钮后跳转路由需要传参购物详情参数,采用哪种方式?query?params?

答案:其实都可以,但是最优雅的还是采用query方式,具体效果看如下:

  • 首先是采用params方式,地址栏显示的是地址字符串,但组件中控制台打印居然也能正确解析,说明能获取到参数,但是URL看起来一大长串东西还是不优雅,万一后续URL一顿追加参数,岂不是越来越长根本不优雅。

在这里插入图片描述

  • 而采用query方式,地址栏很清爽,所以推荐采用这种方式传参。

在这里插入图片描述

注意点2:

问题:参数传递采用本地存储好还是会话存储好?

答案:推荐采用会话存储,localStorage本地存储会在硬盘保留一份需手动清除,而sessionStorage会话存储随着浏览器窗口关闭就清楚了,使用方便。

注意点3:

问题:无论是本地存储还是会话存储,可以存对象吗?

答案:不能,只能存json字符串,直接存对象会无法解析。

  • 存储存对象效果,这东西无法解析:

在这里插入图片描述

29.3购物车

购物车

  • 购物车静态组件-需要修改样式结构(删除第三项并调整css让各个项目对齐,比例为:15 35 10 17 10 13)
  • 向服务器发送ajax请求,获取购物车数据
  • UUID临时游客身份
  • 动态展示购物车

29.3.1 向服务器发送ajax请求,获取购物车数据

修改代码:

src/api/index.js

//获取购物车列表数据接口
//URL:/api/cart/cartList   method:get
export const reqCartList = ()=>requests({url:'/cart/cartList ',method:'get'});

src/store/index.js

import shopCar from "@/store/shopCar"modules:{...shopCar}

src/store/shopCar/index.js

import {reqCartList} from "@/api";//shopCar模块的小仓库
//actions代表一系列动作,可以书写自己的业务逻辑,也可以处理异步
const actions = {async reqCartList({commit}) {let response = await reqCartList();if (response.code == 200) {commit("REQ_CART_LIST", response.data)}},}
//mutations代表维护,操作维护的是state中的数据,且state中数据只能在mutations中处理
const mutations = {REQ_CART_LIST(state, carList) {state.carList = carList},
}
//state代表仓库中的数据
const state = {//购物车列表carList: [],
}
//计算属性
//项目当中getters主要的作用是:简化仓库中的数据(简化数据而生)
//可以把我们将来在组件当中需要用的数据简化一下【将来组件在获取数据的时候就方便了】
const getters = {carList(state) {return state.carList[0] || {};}
}//创建并暴露store
export default {actions,mutations,state,getters
}

src/pages/ShopCart/index.vue

methods: {getData() {this.$store.dispatch('reqCartList')},},
mounted() {this.getData()
}

注意点1:如图,这一列多余,删除第三项并调整css让各个项目对齐,比例为:15 35 10 17 10 13

在这里插入图片描述

注意点2:

问题:向服务器发送查询购物车ajax请求,获取购物车数据,为啥返回数据是空呢?

答案:因为你得带UUID的东西,后端不知道你谁,也就不知道把那条数据返回给你了。

29.3.2UUID临时游客身份

安装命令:cnpm install --save uuid

修改代码:

src/utils/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);}//切记有返回值,没有返回值undefinedreturn uuid_token;
}

src/api/axios.js

//在当前模块中引入store
import store from '@/store';
if(store.state.detail.uuid_token){//请求头添加一个字段(userTempId):和后台老师商量好了config.headers.userTempId = store.state.detail.uuid_token;
}

src/store/detail/index.js

const state = {//游客临时身份uuid_token: getUUID()
}

注意点1:

问题:假设现在我有UUID了,那如何传过去呢?接口已经定义好了只有2个参数,UUID咋传过去?

答案:可以放在请求头header中传递过去。

注意点2:

问题:我如何使用UUID第三方插件呢?

答案:登录npm官网https://www.npmjs.com/package/uuid搜索uuid,下方就是使用方式。

在这里插入图片描述

注意点3:切记UUID不能在vuex中生成,因为vuex是每次触发就会随机生成,会变动这是不行的,正常应该是一次生成有效期内不改变。所以这个uuidv4()不能放在vuex中,最好放在src目录下新建一个文件夹utils,这个文件夹里面经常放一些常用的功能模块,比如正则、临时身份UUID等等。

注意点4:切记src/utils/uuid_token.js下封装的uuid方法一定要有返回值,否则返回值是underfine无效的。

注意点5:

问题:在src/api/axios.js中现在需要给请求头header添加uuid,但是uuid在vuex仓库中,如何获取呢?

答案:在src/api/axios.js中引入import store from ‘@/store’;,通过store 对象可以获取仓库中的state属性。

29.3.3动态展示购物车

修改代码:

src/pages/ShopCart/index.vue

<ul class="cart-list" v-for="(car, index) in cartInfoList" :key="car.id">
<input type="checkbox" name="chk_list" :checked="car.isChecked == 1">
<div class="item-msg">{{car.skuName}}</div>
<span class="price">{{car.skuPrice}}.00</span>
<input autocomplete="off" type="text" :value="car.skuNum" minnum="1" class="itxt">
<span class="sum">{{car.skuNum * car.skuPrice}}</span>
<i class="summoney">{{carTotalPrice}}</i>import {mapGetters} from "vuex";
data() {return {totalPrice: 0}},computed: {...mapGetters(["carList"]),//购物车数据cartInfoList() {return this.carList.cartInfoList || []},//计算购买产品的总价carTotalPrice() {this.cartInfoList.forEach(item => {this.totalPrice += item.skuNum * item.skuPrice;})return this.totalPrice;},//判断底部复选框是否勾选【全部产品都选中,采勾选】isAllChecked() {//遍历数组里面原理,只要全部元素isChecked属性都为1===>真 true//只要有一个不是1======>假falsereturn this.cartInfoList.every(item=> item.isChecked == 1)}}

注意点1:

问题:查询购物车信息的接口方法放在哪里?是放在“去购物车结算”按钮还是放在“购物车”页面加载完毕中定义?

答案:放在“购物车”页面加载完毕中定义,只要购物车页面一初始化,甭管哪个入口跳转进来的都能进行批量查询购物车数据并动态展示。

注意点2:购物车左下角的全选按钮判断是否勾选,推荐适用every而不是foreach方法

isAllChecked() {//遍历数组里面原理,只要全部元素isChecked属性都为1===>真 true//只要有一个不是1======>假falsereturn this.cartInfoList.every(item=> item.isChecked == 1)
}

29.4修改购物车产品的数量(需要发请求:参数理解)

修改代码:

src/pages/ShopCart/index.vue

<li class="cart-list-con5"><a href="javascript:void(0)" class="mins" @click="handle('minus', -1, car)">-</a><input autocomplete="off" type="text" :value="car.skuNum" minnum="1" class="itxt" @change="handle('change', $event.target.value * 1, car)"><a href="javascript:void(0)" class="plus" @click="handle('add', 1, car)">+</a>
</li>//引入lodash:是把lodash全部封装好的函数全都引入进来了
//按需引入:只是引入节流函数,其他的函数没有引入(模块),这样做的好处是,当你打包项目的时候体积会小一些
import throttle from "lodash/throttle";
methods: {//修改某一个产品的个数[节流]handle: throttle(async function(flag, disNum, car) {//type:为了区分这三个元素//disNum形参:+ 变化量(1)  -变化量(-1)   input最终的个数(并不是变化量)//cart:哪一个产品【身上有id】//向服务器发请求,修改数量switch (flag) {case "add"://加号disNum = 1;break;case "minus"://判断产品的个数大于1,才可以传递给服务器-1//如果出现产品的个数小于等于1,传递给服务器个数0(原封不动)disNum = car.skuNum > 1 ? -1 : 0;break;case "change":/*用户输入进来的最终量,如果非法的(带有汉字|出现负数),带给服务器数字零* 问题:为啥是disNum < 1,而不是disNum <= 1* 答案:哪怕输入1也会走else里面的代码,不影响功能,所以无需加“=”等于号*/if (isNaN(disNum) || disNum < 1) {disNum = 0;} else {//属于正常情况(小数:取证),带给服务器变化的量 用户输入进来的 - 产品的起始个数disNum = parseInt(disNum) - car.skuNum;}break;}try {//派发actionawait this.$store.dispatch('addOrUpdateShopCar', {skuId: car.skuId, skuNum: disNum})//再一次获取服务器最新的数据进行展示this.getData();} catch (error) {//失败alert(error.message);}}, 500),
}

注意点1:如图,购物车中的【+、-、输入值】都应该触发修改购物车接口,且三个函数是同一个函数

在这里插入图片描述

注意点2:

问题:如何区分是点击了加号、减号、还是输入值呢?

答案:通过传参字符串flag标识名称进行区分。

注意点3:

问题:实际触发修改购物车接口的传值要注意。

答案:点击“+”号应传值(1),点击“-”号应传值(-1),点击输入值应传值(输入值-原始值)。

注意点4:输入框中事件一定要写成@change,而不是@click,否则效果不对。

注意点5:

问题:对于“minus”情况,为啥是disNum < 1,而不是disNum <= 1

答案:哪怕输入1也会走else里面的代码,不影响功能,所以无需加“=”等于号

注意点6:点击减号“-”要加判断,不能让值小于1。

case "minus"://判断产品的个数大于1,才可以传递给服务器-1//如果出现产品的个数小于等于1,传递给服务器个数0(原封不动)disNum = car.skuNum > 1 ? -1 : 0;break;

注意点7:对于“change”情况,也要加判断

case "change":/*用户输入进来的最终量,如果非法的(带有汉字|出现负数),带给服务器数字零* 问题:为啥是disNum < 1,而不是disNum <= 1* 答案:哪怕输入1也会走else里面的代码,不影响功能,所以无需加“=”等于号*/  if (isNaN(disNum) || disNum < 1) {disNum = 0;} else {//属于正常情况(小数:取证),带给服务器变化的量 用户输入进来的 - 产品的起始个数disNum = parseInt(disNum) - car.skuNum;}break;

注意点8:

问题:连续点击,居然能出现负数,而慢慢点击就不会出问题,为什么?

在这里插入图片描述

答案:因为没有加“节流”效果,由于点击过快就会出现这种错误现象。

旧代码:

//修改某一个产品的个数[节流]async handle(flag, disNum, car) {//type:为了区分这三个元素//disNum形参:+ 变化量(1)  -变化量(-1)   input最终的个数(并不是变化量)//cart:哪一个产品【身上有id】//向服务器发请求,修改数量switch (flag) {case "add"://加号disNum = 1;break;case "minus"://判断产品的个数大于1,才可以传递给服务器-1//如果出现产品的个数小于等于1,传递给服务器个数0(原封不动)disNum = car.skuNum > 1 ? -1 : 0;break;case "change":/*用户输入进来的最终量,如果非法的(带有汉字|出现负数),带给服务器数字零* 问题:为啥是disNum < 1,而不是disNum <= 1* 答案:哪怕输入1也会走else里面的代码,不影响功能,所以无需加“=”等于号*/if (isNaN(disNum) || disNum < 1) {disNum = 0;} else {//属于正常情况(小数:取证),带给服务器变化的量 用户输入进来的 - 产品的起始个数disNum = parseInt(disNum) - car.skuNum;}break;}try {//派发actionawait this.$store.dispatch('addOrUpdateShopCar', {skuId: car.skuId, skuNum: disNum})//再一次获取服务器最新的数据进行展示this.getData();} catch (error) {//失败alert(error.message);}},

修改后代码

//引入lodash:是把lodash全部封装好的函数全都引入进来了
//按需引入:只是引入节流函数,其他的函数没有引入(模块),这样做的好处是,当你打包项目的时候体积会小一些
import throttle from "lodash/throttle";//修改某一个产品的个数[节流]handle: throttle(async function(flag, disNum, car) {//type:为了区分这三个元素//disNum形参:+ 变化量(1)  -变化量(-1)   input最终的个数(并不是变化量)//cart:哪一个产品【身上有id】//向服务器发请求,修改数量switch (flag) {case "add"://加号disNum = 1;break;case "minus"://判断产品的个数大于1,才可以传递给服务器-1//如果出现产品的个数小于等于1,传递给服务器个数0(原封不动)disNum = car.skuNum > 1 ? -1 : 0;break;case "change":/*用户输入进来的最终量,如果非法的(带有汉字|出现负数),带给服务器数字零* 问题:为啥是disNum < 1,而不是disNum <= 1* 答案:哪怕输入1也会走else里面的代码,不影响功能,所以无需加“=”等于号*/if (isNaN(disNum) || disNum < 1) {disNum = 0;} else {//属于正常情况(小数:取证),带给服务器变化的量 用户输入进来的 - 产品的起始个数disNum = parseInt(disNum) - car.skuNum;}break;}try {//派发actionawait this.$store.dispatch('addOrUpdateShopCar', {skuId: car.skuId, skuNum: disNum})//再一次获取服务器最新的数据进行展示this.getData();} catch (error) {//失败alert(error.message);}}, 500),

29.5删除某一产品

修改代码:

app/src/api/index.js

//删除购物产品的接口
//URL:/api/cart/deleteCart/{skuId}   method:DELETE
export const reqDeleteCartById = (skuId)=>requests({url:`/cart/deleteCart/${skuId}`,method:'delete'});

src/store/shopCar/index.js

import {reqDeleteCartById} from "@/api";const actions = {//删除购物车某一个产品async reqDeleteCartById({commit}, skuId) {let response = await reqDeleteCartById(skuId);if (response.code == 200) {//返回的是成功的标记return "OK";} else {//返回的是失败的标记return Promise.reject(new Error("fail"))}}
}

src/pages/ShopCart/index.vue

<a class="sindelet" @click="reqDeleteCartById(car.skuId)">删除</a>//删除某一个产品的操作
async reqDeleteCartById(skuId) {try {//派发actionawait this.$store.dispatch('reqDeleteCartById', skuId)this.getData();} catch (error) {alert(error.message)}
}

29.6修改产品状态

修改代码:

app/src/api/index.js

//修改商品的选中状态
//URL:/api/cart/checkCart/{skuId}/{isChecked}   method:get
export const reqUpdateCheckedByid = (skuId,isChecked)=>requests({url:`/cart/checkCart/${skuId}/${isChecked}`,method:'get'});

src/store/shopCar/index.js

import {reqUpdateCheckedByid} from "@/api";const actions = {//修改购物车某一个产品的选中状态async reqUpdateCheckedByid({commit}, {skuId,isChecked}) {let response = await reqUpdateCheckedByid(skuId,isChecked);if (response.code == 200) {//返回的是成功的标记return "OK";} else {//返回的是失败的标记return Promise.reject(new Error("fail"))}},
}

src/pages/ShopCart/index.vue

<input type="checkbox" name="chk_list" :checked="car.isChecked == 1" @change="reqUpdateCheckedByid(car.skuId, $event)">//修改某个产品的勾选状态async reqUpdateCheckedByid(skuId, event) {try {//如果修改数据成功,再次获取服务器数据(购物车)let isChecked = event.target.checked ? "1" : "0";//派发actionawait this.$store.dispatch('reqUpdateCheckedByid', {skuId: skuId, isChecked})this.getData();} catch (error) {alert(error.message)}},

29.7删除全部选中的商品

修改代码:

src/pages/ShopCart/index.vue

<a @click="deleteAllCheckedCar">删除选中的商品</a>//删除全部选中的产品
//这个回调函数咱门没办法手机到一些有用数据
async deleteAllCheckedCar() {try {//成功//派发一个actionawait this.$store.dispatch('deleteAllCheckedCar')//再发请求获取购物车列表this.getData()} catch (error) {//失败alert(error.message)}
}

src/store/shopCar/index.js

//删除全部勾选的产品
async deleteAllCheckedCar({dispatch, getters}) {//context:小仓库,commit【提交mutations修改state】 getters【计算属性】 dispatch【派发action】 state【当前仓库数据】//获取购物车中全部的产品(是一个数组)let primoseAll = [];getters.carList.cartInfoList.forEach(item => {let promise = item.isChecked == 1 ? dispatch('reqDeleteCartById', item.skuId) : '';//将每一次返回的Promise添加到数组当中primoseAll.push(promise);})//只要全部的p1|p2....都成功,返回结果即为成功//如果有一个失败,返回即为失败结果return Promise.all(primoseAll);}

注意点1:接口API未提供选中删除的功能,只提供了单独删除的,所以可以采用批量循环删除的方式。

注意点2:dispatch派发不仅可以存在于vue中使用,也可以在vuex仓库中使用

注意点3:vuex仓库中的context包含很多东西,包括【commit、dispatch、getters、state…】,具体如图

在这里插入图片描述

注意点4:Promise.all用法,all里面的是个数组,如果其中的子项promise有一个失败,返回即为失败结果。具体用法如下:

let primoseAll = [];
let promise = item.isChecked == 1 ? dispatch('reqDeleteCartById', item.skuId) : '';
//将每一次返回的Promise添加到数组当中
primoseAll.push(promise);
//只要全部的p1|p2....都成功,返回结果即为成功
//如果有一个失败,返回即为失败结果
return Promise.all(primoseAll);

29.8全选操作

修改代码:

src/pages/ShopCart/index.vue

<input class="chooseAll" type="checkbox" :checked="isAllChecked && cartInfoList.length > 0" @click="updateAllCheckedCar($event.target.checked)">//修改全部产品的选中状态
async updateAllCheckedCar(checked) {try {//成功//派发一个actionlet isChecked = checked ? "1" : "0";await this.$store.dispatch('updateAllCheckedCar', isChecked)//再发请求获取购物车列表this.getData()} catch (error) {//失败alert(error.message)}
},

src/store/shopCar/index.js

//修改全部产品的状态
async updateAllCheckedCar({dispatch, getters}, isChecked) {//context:小仓库,commit【提交mutations修改state】 getters【计算属性】 dispatch【派发action】 state【当前仓库数据】//获取购物车中全部的产品(是一个数组)let primoseAll = [];getters.carList.cartInfoList.forEach(item => {let promise = dispatch('reqUpdateCheckedByid', {skuId:item.skuId, isChecked});//将每一次返回的Promise添加到数组当中primoseAll.push(promise);})//只要全部的p1|p2....都成功,返回结果即为成功//如果有一个失败,返回即为失败结果return Promise.all(primoseAll);}

注意点1:全选或全不选后的正确效果如图

在这里插入图片描述

注意点2:

问题:全部删除后,左下角的勾选按钮居然还是选中状态,需要优化

答案:在后面多补充个cartInfoList.length > 0判断条件即可

:checked="isAllChecked && cartInfoList.length > 0

本人其他相关文章链接

1.vue尚品汇商城项目-day04【24.点击搜索按钮跳转后的页面商品列表、平台售卖属性动态展示(开发Search组件)】
2.vue尚品汇商城项目-day04【25.面包屑处理关键字】
3.vue尚品汇商城项目-day04【26.排序操作(难点)】
4.vue尚品汇商城项目-day04【27.分页器静态组件(难点)】
5.vue尚品汇商城项目-day04【28.详情页面Detail】
6.vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

相关文章:

vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

文章目录29.加入购物车操作&#xff08;难点&#xff09;29.1加入购物车按钮29.2addCartSuce29.3购物车29.3.1 向服务器发送ajax请求&#xff0c;获取购物车数据29.3.2UUID临时游客身份29.3.3动态展示购物车29.4修改购物车产品的数量&#xff08;需要发请求&#xff1a;参数理解…...

KubeSphere 社区双周报 | 4.8 深圳站 Meetup 火热报名中 | 2023.3.17-3.30

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.03.17-2023.…...

ChatGPT热炒之前 搜索引擎SEO算法已经悄然改变

2022年4月起&#xff0c;某度算法有了新的调整&#xff0c;这对于靠SEO获得流量的公司简直可以说是灭顶之灾。原本SEO从业者还指望跟之前一样&#xff0c;等算法调整稳定后&#xff0c;网站的自然排名还会再回来&#xff0c;但等到了10月份&#xff0c;仍然没有回暖的迹象&…...

【Linux】Mysql之视图的基本操作

一、什么是视图 MySQL 视图&#xff08;View&#xff09;是一种虚拟存在的表&#xff0c;同真实表一样&#xff0c;视图也由列和行构成&#xff0c; 但视图并不实际存在于数据库中。行和列的数据来自于定义视图的查询中所使用的 表&#xff0c;并且还是在使用视图时动态生成的。…...

《扬帆优配》西藏地震!美史上最严排放新规将出台,美股收涨

当地时间周四&#xff0c;美股遍及收高&#xff0c;科技股领涨。因耶稣受难日&#xff0c;美股4月7日&#xff08;周五&#xff09;休市&#xff0c;周四为美股本周最终一个买卖日&#xff0c;从本周状况来看&#xff0c;纳指与标普500指数均录得跌幅&#xff0c;别离跌1.1%和0…...

Python 小型项目大全 66~70

六十六、简单替换密码 原文&#xff1a;http://inventwithpython.com/bigbookpython/project66.html 简单替换密码用一个字母代替另一个字母。由于字母A有 26 种可能的替换&#xff0c;B有 25 种可能的替换&#xff0c;C有 24 种可能的替换&#xff0c;等等&#xff0c;所以可能…...

Barra模型因子的构建及应用系列八之Earning_Yeild因子

一、摘要 在前期的Barra模型系列文章中&#xff0c;我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子、NonLinear Size因子、Book-to-Price因子和Liquidity因子&#xff0c;并分别创建了对应的单因子策略&#xff0c;其中Size因子和NonLinear Siz因子具有…...

2022蓝桥杯省赛——卡片

问题描述 小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有两位同学的卡片都是一样的。 给定 n, 请问小蓝的卡片至少有多少种? 输入格式 输入一行包含一个正整数表示 n 。 输出…...

数据结构-快速排序

一.概要 快速排序是一种基于分治思想的排序算法&#xff0c;其基本思路是选取一个基准值&#xff08;pivot&#xff09;&#xff0c;通过一趟排序将待排序列分成两个部分&#xff0c;其中左半部分都小于基准值&#xff0c;右半部分都大于基准值&#xff0c;然后对左右两部分分…...

WuThreat身份安全云-TVD每日漏洞情报-2023-04-10

漏洞名称:Apple iOS/iPadOS 越界写入 漏洞级别:高危 漏洞编号:CVE-2023-28206 相关涉及:Apple iOS <16.4.0 漏洞状态:在野 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-08810 漏洞名称:PHPGurukul Bank Locker Management System SQL 注入 漏洞级别:高…...

IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决

IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决 注意&#xff1a;实验环境的IDEA版本&#xff1a;2021.3.1 1、问题描述 1.1、当想看源码时&#xff0c;点击Download Sources 1.2、此时出现了Cannot download sources 2、解决办法 2.1、…...

R+VIC模型融合实践技术应用及未来气候变化模型预测/SWAT/HSPF/HEC-HMS

在气候变化问题日益严重的今天&#xff0c;水文模型在防洪规划&#xff0c;未来预测等方面发挥着不可替代的重要作用。目前&#xff0c;无论是工程实践或是科学研究中都存在很多著名的水文模型如SWAT/HSPF/HEC-HMS等。虽然&#xff0c;这些软件有各自的优点&#xff1b;但是&am…...

Python 02 数据类型(04元组)

一、元组 元组和列表的唯一不同&#xff1a;不能直接对元组的元素进行修改&#xff0c;删除&#xff0c;添加。 不能修改 1.1 创建元组 1.1.1 创建一个空元组 touple1() # ‘() 里面没有元素&#xff0c;表示为空元组 1.1.2 元组可以容纳任意数据类型的数据的有序集合&…...

WMS:入库库作业流程状态定位

系列文章目录 例如&#xff1a;第一章 WMS&#xff1a;入库库作业流程状态定位 目录 系列文章目录 文章目录 前言 一、入库订单作业状态 二、入库任务级作业状态 1.收货作业 2.验收作业 总结 前言 WMS系统在仓储作业的管理中发挥着至关重要的作用&#xff0c;其核心优势在于强大…...

蓝易云:Linux系统【Centos7】如何配置完整的CC攻击防护策略

完整的CC攻击防护策略包括以下步骤&#xff1a; 1. 调整内核参数 在CentOS 7系统中&#xff0c;可以通过修改内核参数来增加系统对CC攻击的抵抗力。具体操作如下&#xff1a; &#xff08;1&#xff09;打开sysctl.conf文件&#xff1a; vim /etc/sysctl.conf &#xff08…...

编解码持续升级,「硬」实力铸就视频云最优解

算力时代&#xff0c;视频云需要怎样的 CPU&#xff1f; 在数据爆发式增长及算法日益精进的大背景下&#xff0c;属于「算力」的时代俨然到来。随着视频成为互联网流量的主角&#xff0c;日趋饱和的音视频场景渗透率、人类对“感官之限”的追求与突破、更多元化的场景探索及技术…...

贵金属技术分析的止损保护

前面说过我们这些小散户&#xff0c;最多也不过十几万或者几万美金的账户&#xff0c;没有必要想国际的一些大基金那样&#xff0c;又锁仓&#xff0c;又对冲什么的&#xff0c;我们资金小的投资者&#xff0c;足够灵活&#xff0c;自然有我们存活的方法。所以我们要注意发挥我…...

Python 进阶指南(编程轻松进阶):三、使用 Black 工具来格式化代码

原文&#xff1a;http://inventwithpython.com/beyond/chapter3.html 代码格式化是将一组规则应用于源代码&#xff0c;从而使得代码风格能够简洁统一。虽然代码格式对解析程序的计算机来说不重要&#xff0c;但代码格式对于可读性是至关重要的&#xff0c;这是维护代码所必需的…...

计算机应用辅导大纲及真题

00019考试 湖北省高等教育自学考试实践&#xff08;技能&#xff09;课程大纲 课程名称&#xff1a;计算机应用基础&#xff08;实践&#xff09; 课程代码&#xff1a;00019 实践能力的培养目标。 计算机应用基础&#xff08;实践&#xff09;是高等教育自学考试多…...

【Go基础】一篇文章带你全面了解学习—切片

目录 1、切片注意点 2、声明切片 3、切片初始化 4、切片的内存布局...

2022国赛28:centos8.5离线安装docker

大赛试题内容: 八、虚拟化(20分) 在Linux2上安装docker-ce,导入centos镜像。软件包和镜像存放在物理机D:\soft\DockerLinux。创建名称为skills的容器,映射Linux2的80端口到容器的80端口,在容器内安装apache2,默认网页内容为“HelloContainer”。解答过程: 下载CENTOS8镜…...

JVM专题

JVM类加载 Java里有如下几种类加载器&#xff1a; 引导类加载器&#xff1a;负责加载支撑JVM运行的位于JRE的lib目录下的核心类库&#xff0c;比如 rt.jar、charsets.jar等 扩展类加载器&#xff1a;负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包应用程序…...

蓝桥杯模板题目

A:::::::::::::::小王子单链表&#xff08;链表&#xff09; 题目描述 小王子有一天迷上了排队的游戏&#xff0c;桌子上有标号为 1−10 的 10 个玩具&#xff0c;现在小王子将他们排成一列&#xff0c;可小王子还是太小了&#xff0c;他不确定他到底想把那个玩具摆在哪里&…...

SAP IDT - Building Data Foundation

To build a Data Foundation, it can be created on a Local Project view. Right-click under Local Project → New → Data Foundation. You can select a Single-source enabled or Multi-source enabled. Follow the wizard and select the connections. Data Foundatio…...

【Python】【进阶篇】三、Python爬虫的构建User-Agnet代理池

目录三、Python爬虫的构建User-Agnet代理池3.1 自定义UA代理池3.2 模块随机获取UA三、Python爬虫的构建User-Agnet代理池 在编写爬虫程序时&#xff0c;一般都会构建一个 User-Agent &#xff08;用户代理&#xff09;池&#xff0c;就是把多个浏览器的 UA 信息放进列表中&…...

数据结构.双链表的各种操作

//双链表 //单链表无法逆向检索&#xff0c;双链表可进可退 双链表比单链表多啦一个前驱指针 //双链表查找时间复杂度都为o(n) #include<bits/stdc.h> using namespace std; typedef struct donde //创建双链表 {int data;dnode *next,*prior; //前驱和后继 }dnode,*…...

去年12月被无情辞退,三个月后我携手自动化测试神技王者归来

引言 不知不觉在软件测试行业工作了3年之久&#xff0c;虽然说我是主做的功能测试&#xff0c;但是我也一直是兢兢业业的呀&#xff0c;不曾想去年7月份无情被辞的消息让我感到一阵沉重。我曾经一直坚信自己的技能和经验足以支撑我在这个领域的未来&#xff0c;但现实却告诉我&…...

区块链技术之共识机制

“共识机制”一词通常通俗地用于指代“股权证明”、“工作证明”或“权威证明”协议。然而&#xff0c;这些只是防止女巫攻击的共识机制的组成部分&#xff0c;共识机制是思想、协议和激励的完整堆栈&#xff0c;使一组分布式节点能够就区块链的状态达成一致。共识机制是区块链…...

SpringCloud断路器——Hystrix

Hystrix 本专栏学习内容来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 简介 Hystrix是一个用于处理分布式系统的延迟和容错的一个开源库&#xff0c;在分布式系统里&#xff0c;许多依赖不可避免的会调用失败&#xff0c;比如超时、异常等&#xff0c;Hystrix…...

分布式 - 分布式体系架构:集群和分布式

文章目录01. 什么是集群&#xff1f;02. 集群为什么可以提高系统的可靠性&#xff1f;03. 集群为什么可以提高系统的性能&#xff1f;04. 什么是分布式计算&#xff1f;05. 如何进行分布式计算&#xff1f;06. 集群如何提高计算效率&#xff1f;07. 集群的优点和缺点&#xff1…...