微信小程序 ---- 慕尚花坊 购物车

购物车

01. 购物车-封装购物车接口 API

思路分析:

为了方便后续进行购物车模块的开发,我们在这一节将购物车所有的接口封装成接口 API 函数

落地代码:

import http from '../utils/http'/*** @description 获取购物车列表数据* @returns Promise*/
export const reqCartList = () => {return http.get('/mall-api/cart/getCartList')
}/*** @description 加入购物车* @param {*} data* @returns Promise*/
export const reqAddCart = (data) => {return http.get(`/cart/addToCart/${data.goodsId}/${data.count}`, data)
}/*** @description 更新商品的选中状态* @param {*} goodsId 商品 id* @param {*} isChecked 商品的选中状态* @returns Promise*/
export const reqUpdateChecked = (goodsId, isChecked) => {return http.get(`/cart/checkCart/${goodsId}/${isChecked}`)
}/*** @description 全选和全不选* @param {*} isChecked 商品的选中状态* @returns Promise*/
export const reqCheckAllCart = (isChecked) => {return http.get(`/cart/checkAllCart/${isChecked}`)
}/*** @description 删除购物车商品* @param {*} goodsId 商品 id* @returns Promise*/
export const reqDelCart = (goodsId) => {return http.get(`/cart/delete/${goodsId}`)
}

02. 加入购物车-模板分析和渲染

业务介绍

点击加入购物车和立即购买的时候,展示购物弹框,在弹框中需要用户选择购买数量和祝福语

点击加入购物车和立即购买,触发的是同一个弹框。

因此点击弹框中的确定按钮时,我们需要区分当前是加入购物车操作还是立即购买操作。

这时候定义一个状态 buyNow 做区分,buyNow 等于 1 代表是立即购买,否则是加入购物车

产品需求

  1. 如果点击的是加入购物车,需要将当前商品加入到购物车

  2. 如果点击的是立即购买,需要跳转到结算支付页面,立即购买该商品

  3. 如果是立即购买,不支持购买多个商品

结构分析

点击立即购买和加入购物车的时候,通过 show 属性,控制弹框的隐藏和展示

<!-- 商品的底部商品导航 -->
<van-goods-action><!-- coding... -->
+   <van-goods-action-button text="加入购物车" type="warning" bindtap="handleAddcart" />
+   <van-goods-action-button text="立即购买" bindtap="handeGotoBuy" />
</van-goods-action><!-- 加入购物车、立即购买弹框 -->
<!-- show 控制弹框的隐藏和展示 -->
<!-- bind:close 点击关闭弹框时触发的回调 -->
<van-action-sheet show="{{ show }}" bind:close="onClose"><view class="sheet-wrapper"><!-- 代码略... --><!-- 购买数量弹框 -->
+     <view class="buy-btn" wx:if="{{ buyNow === 0 }}"><!-- Stepper 步进器,由增加按钮、减少按钮和输入框组成,控制购买数量 --><van-stepper value="{{ count }}" bind:change="onChangeGoodsCount" /></view><!-- 代码略... --></view>
</van-action-sheet>

点击立即购买和加入购物车的时候,通过 buyNow 属性,来区分是进行的某种操作

Page({// 页面的初始数据data: {goodsInfo: {}, // 商品详情show: false, // 加入购物车和立即购买时显示的弹框count: 1, // 商品购买数量,默认是 1blessing: '', // 祝福语
+     buyNow: '' // 是否立即购买},// 加入购物车handleAddcart() {this.setData({show: true,
+       buyNow: 0})},// 立即购买handeGotoBuy() {this.setData({show: true,
+       buyNow: 1})},// 代码略...
})

03. 加入购物车-关联 Store 对象

思路分析:

当用户点击加入购物车 或者 立即购买时,需要判断用户是否进行了登录。

我们需要使用 Token 进行判断,因此需要让页面和 Store 对象建立关联。

这时候可以使用 BehaviorWithStore 让页面 和 Store 对象建立关联。

落地代码:

➡️ /behaviors/userBehavior.js

// 导入 BehaviorWithStore 让页面和 Store 对象建立关联
import { BehaviorWithStore } from 'mobx-miniprogram-bindings'
// 导入用户 Store
import { userStore } from '@/stores/userstore'export const userBehavior = BehaviorWithStore({storeBindings: {store: userStore,fields: ['token']}
})

➡️ /behaviors/userBehavior.js

import { reqGoodsInfo } from '@/api/goods'
import { reqAddCart } from '@/api/cart'
+ import { userBehavior } from '@/behaviors/userBehavior'Page({
+   behaviors: [userBehavior],// 代码略...
})

04. 加入购物车和立即购买区分处理

思路分析:

点击加入购物车以及立即购买以后,需要先判断是否进行了登录,如果用户没有登录过,需要先跳转到登录页面进行登录。

如果点击的是 加入购物车,我们只需要调用 加入购物车 接口即可 (需要获取商品的 ID 、购买数量、祝福语)

如果点击的是 立即购买,我们需要携带参数跳转到商品结算页面 (获取商品的 ID 以及 祝福语跳转到结算页面)

购买数量的限制有 4 个限制,这 4 个限制直接使用 Vant 组件提供的属性进行限制即可:

  1. 必须是正整数,最小是1,最大是200
  2. 若输入小于1,则重置为1
  3. 若输入大于200,则重置为200
  4. 若输入的是其他值,则重置为1

实现步骤:

  1. Stepper 步进器组件,通过value设置输入值,同时绑定change事件,并将值同步到 data
  2. 根据接口文档,导入封装的购物车的接口 API
  3. 点击弹框按钮的时候,判断点击的加入购物车还是立即购买,执行不同的操作

落地代码:

➡️ /modules/goodsModule/pages/detail/detail.html

<van-steppervalue="{{ count }}"
+  integer
+  min="1"
+  max="200"bind:change="onChangeGoodsCount"
/>

➡️ /modules/goodsModule/pages/detail/detail.js

// 监听是否更改了购买数量
onChangeGoodsCount(event) {// 将最新的购买数量同步到 datathis.setData({count: Number(event.detail)})
},// 弹框的确定按钮
async handleSubmit() {// 解构获取数据const { token, count, blessing, buyNow } = this.dataconst goodsId = this.goodsId// 如果没有 token ,让用户新登录if (!this.data.token) {wx.navigateTo({url: '/pages/login/login'})return}// 将用户输入的值转成 Number 类型const count = Number(event.detail)// 验证购买数量的正则const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/// 使用正则验证const res = reg.test(count)// 如果验证没有通过,直接返回,不执行后续的逻辑if (!res) return// 加入购物车if (buyNow === 0) {// 加入购物车const res = await reqAddGood({ goodsId, count, blessing })if (res.code === 200) {wx.showToast({title: '加入购物车成功'})this.setData({show: false})}} else {// 立即购买wx.navigateTo({url: `/pages/order/detail/index?goodsId=${goodsId}&blessing=${blessing}`})}
}

05. 加入购物车-展示购物车购买数量

思路分析

判断用户是否进行了登录。

如果没有登录过,则不展示购物车商品的数量。

如果用户登录过,则需要展示购物车商品的数量,则获取购物车列表数据,通过累加计算得出商品购买数量

实现步骤

  1. 进入商品详情,调用方法,在方法中判断token是否存在
  2. 如何存在,则获取购物车列表数据,通过累加计算得出商品购买数量,展示购买的数量
  3. 不存在,不执行任何逻辑,

落地代码

➡️ /modules/goodsModule/pages/detail/detail.js

Page({data: {// coding...
+     allCount: '' // 购物车商品总数量},// 弹框的确定按钮async handleSubmit() {// 如果没有 token ,让用户新登录if (!this.data.token) {wx.navigateTo({url: '/pages/login/login'})return}// 解构获取数据const { count, blessing, allCount } = this.dataconst goodsId = this.goodsId// 加入购物车if (this.data.buyNow === 0) {// 加入购物车const res = await reqAddCart({ goodsId, count, blessing })if (res.code === 200) {wx.toast({title: '加入购物车成功',icon: 'success',mask: false})+         // 购物车购买数量合计
+         this.getCartCount()this.setData({show: false})}} else {// 立即购买wx.navigateTo({url: `/pages/order/detail/detail?goodsId=${goodsId}&blessing=${blessing}`})}},+   // 计算购买数量
+   async getCartCount() {
+     // 如果没有 token ,说明用户是第一次访问小程序,没有进行登录过
+     if (!this.data.token) return
+ 
+     // 获取购物的商品
+     const res = await reqCartList()
+ 
+     if (res.data.length !== 0) {
+       // 购物车商品累加
+       let allCount = 0
+ 
+       // 获取购物车商品数量
+       res.data.forEach((item) => {
+         allCount += item.count
+       })
+ 
+       // 将购物车购买数量赋值
+       this.setData({
+         // 展示的数据要求是字符串
+         allCount: (allCount > 99 ? '99+' : allCount) + ''
+       })
+     }
+   },onLoad(options) {// 接收传递的商品 ID,并且将 商品 ID 挂载到 this 上面this.goodsId = options.goodsId// 调用获取商品详情数据的方法this.getGoodsInfo()+     // 计算购买数量
+     this.getCartCount()}// coding...
})

06. 购物车-购物车关联 Store 对象

思路分析:

当用户进入购物车页面时时,需要判断用户是否进行了登录来控制页面的展示效果

这时候我们就需要使用 Token 进行判断,因此需要让页面和 Store 对象建立关联。

因为购物车页面采用的 Component 方法进行构建

这时候可以使用 ComponentWithStore 让页面 和 Store 对象建立关联。

落地代码:

➡️/pages/cart/components/cart.js

+ import { ComponentWithStore } from 'mobx-miniprogram-bindings'
+ import { userStore } from '@/stores/userstore'
+ import { reqCartList } from '@/api/cart'+ ComponentWithStore({
+   storeBindings: {
+     store: userStore,
+     fields: ['token']
+   },// 组件的初始数据data: {cartList: [],emptyDes: '还没有添加商品,快去添加吧~'},+   // 组件的方法列表
+   methods: {
+     // 处理页面的展示
+     async showTipList() {
+       // 将 token 进行解构
+       const { token } = this.data
+
+ 		console.log(token)
+     },onShow() {
+       this.showTipList()}}
})

07. 购物车-获取并渲染购物车列表

思路分析:

  1. 如果没有进行登录,购物车页面需要展示文案:您尚未登录,点击登录获取更多权益

  2. 如果用户进行登录,获取购物车列表数据

    • 购物车没有商品,展示文案: 还没有添加商品,快去添加吧~

    • 购物车列表有数据,需要使用数据对页面进行渲染

实现步骤:

  1. 导入封装好的获取列表数据的 API 函数
  2. onShow 钩子中,根据产品的需求,处理页面的提示
  3. 在获取到数据以后,使用后端返回的数据对页面进行渲染

落地代码:

➡️/pages/cart/cart.js

import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'
import { reqCartList } from '@/api/cart'ComponentWithStore({storeBindings: {store: userStore,fields: ['token']},// 组件的初始数据data: {cartList: [],emptyDes: '还没有添加商品,快去添加吧~'},// 组件的方法列表methods: {
+     // 获取购物车列表数据 + 处理页面的展示
+     async showTipGetList() {
+       // 将 token 进行解构
+       const { token } = this.data
+ 
+       // 1. 如果没有登录,购物车列表,展示文案:您尚未登录,点击登录获取更多权益
+       if (!token) {
+         this.setData({
+           emptyDes: '您尚未登录,点击登录获取更多权益',
+           cartList: []
+         })
+ 
+         return
+       }
+ 
+       // 获取商品列表数据
+       const { data: cartList, code } = await reqCartList()
+ 
+       if (code === 200) {
+         // 2. 如果用户登录,购物车列表为空,展示文案: 还没有添加商品,快去添加吧~
+         this.setData({
+           cartList,
+           emptyDes: cartList === 0 && '还没有添加商品,快去添加吧~'
+         })
+       }
+     },// 页面展示时触发onShow() {
+       this.showTipGetList()}}
})

➡️/pages/cart/components/cart.wxml

<view><viewwx:if="{{ token && cartList.length }}"class="container goods-wrap"bindtap="onSwipeCellPageTap"><view class="cart-wrap">
+       <view class="goods-item" wx:for="{{ cartList }}" wx:key="id"><van-swipe-cell class="goods-swipe" right-width="{{ 65 }}"><view class="goods-info"><view class="left"><van-checkboxchecked-color="#FA4126"
+                 value="{{ item.checked }}"></van-checkbox></view><view class="mid">
+               <image class="img" src="{{ item.imageUrl }}" /></view><view class="right">
+               <view class="title"> {{ item.name }} </view><view class="buy"><view class="price"><view class="symbol">¥</view>
+                   <view class="num">{{ item.price }}</view></view><view class="buy-btn">
+                   <van-stepper value="{{ item.count }}" /></view></view></view></view><view slot="right" class="van-swipe-cell__right">删除</view></van-swipe-cell></view></view><!-- 底部工具栏 --><van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}"><van-checkbox value="{{ true }}" checked-color="#FA4126"> 全选 </van-checkbox></van-submit-bar></view><van-empty wx:else description="{{ emptyDes }}">
+     <navigator url="/pages/index/index" wx:if="{{ token }}">
+       <van-button round type="danger" class="bottom-button">去购物</van-button>
+     </navigator>
+ 
+     <navigator url="/pages/login/login" wx:else>
+       <van-button round type="danger" class="bottom-button">去登录</van-button>
+     </navigator></van-empty>
</view>

08. 购物车-更新商品的购买状态

思路分析:

点击商品的复选框时,更新商品的购买状态。

  1. 获取商品最新的购买状态,将最新的状态同步到服务器(需要调用封装的接口 API 函数,0 不购买,1 购买)
  2. 在服务器更新状态更新成功以后,将本地的数据一并改变。

实现步骤:

  1. 导入封装好的获取列表数据的 API 函数
  2. 当点击切换切换商品状态的时候,调用 reqUpdateGoodStatus,并传参
  3. 在更新成功,将本地的数据一并改变。

落地代码:

➡️ /pages/cart/cart.wxml

<van-checkboxchecked-color="#FA4126"
+   value="{{ item.isChecked }}"
+   bind:change="updateChecked"
+   data-id="{{ item.goodsId }}"
+   data-index="{{ index }}"
></van-checkbox>

➡️ /pages/cart/cart.js

import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'+ import { reqCartList, reqUpdateChecked } from '@/api/cart'Component({// coding...// 组件的方法列表methods: {// 切换商品的选中状态async updateChecked(event) {// 获取最新的选中状态const { detail } = event// 获取商品的索引和 idconst { id, index } = event.target.dataset// 将最新的状态格式化成后端所需要的数据格式const isChecked = detail ? 1 : 0// 调用接口,传入参数,更新商品的状态const res = await reqUpdateChecked(id, isChecked)// 如果数据更新成功,需要将本地的数据一同改变if (res.code === 200) {this.setData({[`cartList[${index}].isChecked`]: isChecked})}},// 获取购物车列表数据async getCartList() {// coding...}}
})

09. 购物车-控制全选按钮的选中状态

思路分析:

购物车列表中每个商品的状态 isCheckd 都是 1,说明每个商品都需要进行购买。

这时候就需要控制底部工具栏全选按钮的选中效果。

基于购物车列表中已有的数据,产生一个新的数据,来控制全选按钮的选中效果,可以使用 计算属性 来实现。

安装 框架拓展 computed

# 安装并构建 框架拓展 computed
npm i miniprogram-computed

实现步骤:

  1. cart 组件中引入 miniprogram-computed ,然后再 behaviors 中进行注册
  2. 新建 computed 配置项,新增 allStatus 函数用来判断是否是全选

落地代码:

➡️ /pages/cart/cart.js

import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'
import { reqCartList, reqUpdateChecked } from '@/api/cart'+ const computedBehavior = require('miniprogram-computed').behaviorComponentWithStore({+   // 注册计算属性
+   behaviors: [computedBehavior],+   computed: {
+     // 判断是否全选
+     // computed 函数中不能访问 this ,只有 data 对象可供访问
+     // 这个函数的返回值会被设置到 this.data.selectAllStatus 字段中
+     selectAllStatus(data) {
+       return (
+         data.cartList.length !== 0 && data.cartList.every((item) => item.isChecked === 1)
+       )
+     }
+   }// 其他代码略...
})

➡️ /pages/cart/cart.wxml

<!-- 底部工具栏 -->
<van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}">
+   <van-checkbox value="{{ selectAllStatus }}" checked-color="#FA4126">全选</van-checkbox>
</van-submit-bar>

10. 购物车-实现全选和全不选功能

思路分析:

点击全选,控制所有商品的选中与全不选效果

  1. 点击全选按钮,获取全选按钮的选中状态(true, false),同时控制所有商品的选中与全不选效果
  2. 在获取到全选按钮状态以后,同时需要将状态同步给服务器 (1 是全选,0 是全不选)
  3. 在服务器更新成功以后,需要将本地的购物车商品选中状态也进行改变

实现步骤:

  1. 导入封装好的全选的 API 函数
  2. 当点击全选和全不选按钮的时候,调用 reqCheckAll,并传参
  3. 在更新成功,将本地的数据一并改变。

落地代码:

➡️ /pages/cart/cart.wxml

<!-- 底部工具栏 -->
<van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}"><van-checkboxvalue="{{ selectAllStatus }}"checked-color="#FA4126"bind:change="changeAllStatus">全选</van-checkbox>
</van-submit-bar>

➡️ /pages/cart/cart.js

ComponentWithStore({// coding...methods: {// coding...// 全选和全不选功能async updateAllStatus(event) {// 获取全选和全不选的状态const isChecked = event.detail ? 1 : 0// 调用接口,更新服务器中商品的状态const res = await reqCheckAllStatus(isChecked)// 如果更新成功,需要将本地的数据一同改变if (res.code === 200) {// 将数据进行拷贝const newCart = JSON.parse(JSON.stringify(this.data.cartList))// 将数据进行更改newCart.forEach((item) => (item.isChecked = isChecked))// 进行赋值this.setData({cartList: newCart})}},// coding...}})

11. 购物车-更新商品购买数量思路分析

思路分析:

在输入框中输入购买的数量,并**不是直接将输入的数量同步给服务器,而是需要计算差值**,服务器端进行处理

差值的计算公式:

差值 = 新值 - 旧值例如:1. 原来是 1,用户输入 11, 差值是:11 - 1 = 10,传递给服务器的是:10,服务器接收到 10 + 1 = 11 
2. 原来是 11,用户输入 5, 差值是:5 - 11 = -6,传递给服务器的是:-6,服务器接收到 -6 + 11 = 5

📌 注意事项:

更新购买数量 和 加入购物车,使用的是同一个接口,为什么加入购物车没有计算差值,

这是因为在加入购物车以后,服务器对商品购买数量直接进行了累加。

例如:之前购物车添加了某个商品,购买数量是 1 个,商品详情又加入 1 个, 直接累加,在购物车显示购买 2 个

12. 购物车-更新商品的购买数量

思路分析:

  1. 必须是正整数,最小是1,最大是200
  2. 如果输入的值大于200,输入框购买数量需要重置为200
  3. 输入的值不合法或者小于1,还原为之前的购买数量
const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/

实现步骤:

  1. 给输入框绑定监听值是否改变的事件,同时传递商品的 ID id 和 商品的购买之前的购买数量 num
  2. 在事件处理程序中获取到最新的数据,然后进行差值的运算
  3. 发送请求即可

落地代码:

➡️ /pages/cart/cart.wxml

<van-stepper
+   integer
+   min="1"
+   max="200"value="{{ item.count }}"
+   data-id="{{ item.goodsId }}"
+   data-oldbuynum="{{ item.count }}"
+   data-index="{{ index }}"
+   bindchange="changeBuyNum"
/>

➡️ /pages/cart/cart.js

// 更新购买的数量
async changeBuyNum(event) {// 获取最新的购买数量,// 如果用户输入的值大于 200,购买数量需要重置为 200// 如果不大于 200,直接返回用户输入的值let buynum = event.detail > 200 ? 200 : event.detail// 获取商品的 ID 和 索引const { id: goodsId, index, oldbuynum } = event.target.dataset// 验证用户输入的值,是否是 1 ~ 200 直接的正整数const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/// 对用户输入的值进行验证const regRes = reg.test(buynum)// 如果验证没有通过,需要重置为之前的购买数量if (!regRes) {this.setData({[`cartList[${index}].count`]: oldbuynum})return}// 如果通过,需要计算差值,然后将差值发送给服务器,让服务器进行逻辑处理const disCount = buynum - oldbuynum// 如果购买数量没有发生改变,不发送请求if (disCount === 0) return// 发送请求:购买的数量 和 差值const res = await reqAddCart({ goodsId, count: disCount })// 服务器更新购买数量成功以后,更新本地的数据if (res.code === 200) {this.setData({[`cartList[${index}].count`]: buynum})}
}

13. 购物车-更新商品购买数量防抖

思路分析:

每次改变购物车购买数量的时候,都会触发 changeBuyNum 事件处理程序,这会频繁的向后端发送请求,给服务器造成压力

我们希望用户在输入最终的购买数量,或者停止频繁点击加、减的以后在发送请求,在将购买数量同步到服务器。

这时候就需要使用 防抖 来进行代码优化。

Licia 是实用 JavaScript 工具库,该库目前拥有超过 400 个模块,同时支持浏览器、node 及小程序运行环境。可以极大地提高开发效率。

licia 官网

licia 中文使用文档

落地代码:

➡️ /pages/cart/cart.js

// 从 miniprogram-licia 导入防抖函数
import { debounce } from 'miniprogram-licia'// 更新购买的数量
+ changeBuyNum: debounce(async function (event) {
+   // 代码略...
+ }, 500)

14. 购物车-购物车商品合计

思路分析:

在订单提交栏位置,展示要购买商品的总金额。

需要判断购物车中哪些商品被勾选,然后将勾选商品的价格进行累加。

当用户更新了商品的状态,或者更新了商品的购买数量,我们都需要重新计算订单总金额。

我们需要基于购物车列表的数据,产生订单总金额,在这里我们使用依然使用 computed 来实现商品合计的功能

实现步骤:

  1. computed 配置项,新增 totalPrice 函数用来计算商品价格总和

落地代码:

➡️ /pages/cart/cart.wxml

<!-- 底部工具栏 -->
<van-submit-barwx:if="{{ cartList.length }}"price="{{ totalPrice }}"button-text="去结算"tip="{{ true }}"
><van-checkboxvalue="{{ selectAllStatus }}"checked-color="#FA4126"bindchange="selectAllStatus">全选</van-checkbox>
</van-submit-bar>

➡️ /pages/cart/cart.js

ComponentWithStore({// coding...// 定义计算属性computed: {// coding...// 计算商品价格总和totalPrice(data) {let totalPrice = 0data.cartList.forEach((item) => {// 如果商品的 isChecked 属性等于,说明该商品被选中的if (item.isChecked === 1) {totalPrice += item.count * item.price}})return totalPrice}},// coding...
})

15. 购物车-删除购物车中的商品

思路分析:

点击删除按钮的时候,需要将对应的购物车商品进行删除

实现步骤:

  1. 导入封装的接口 API 函数,同时导入处理删除自动关闭效果的 behaviors 并进行注册
  2. 在点击删除以后,调用 API 函数,在删除购物车商品成功以后,给用户提示

落地代码:

➡️ /pages/cart/components/cart.wxml

+  <view bindtap="onSwipeCellPage"><!-- 代码略 --><van-swipe-cellclass="goods-swipe"right-width="{{ 65 }}"
+     id="swipe-cell-{{ item.goodsId }}"
+     bind:open="swipeCellOpen"
+     bind:click="onSwipeCellClick"><van-cell-group border="{{ false }}"><view class="goods-info"><view class="left"><van-checkboxchecked-color="#FA4126"value="{{ item.isChecked }}"bindchange="updateChecked"data-id="{{ item.goodsId }}"data-index="{{ index }}"></van-checkbox></view><view class="mid"><image class="img" src="{{ item.imageUrl }}" /></view><view class="right"><view class="title"> {{ item.name }} </view><view class="buy"><view class="price"><view class="symbol">¥</view><view class="num">{{ item.price }}</view></view><view class="buy-btn"><van-steppermin="1"max="200"integervalue="{{ item.count }}"data-id="{{ item.goodsId }}"data-index="{{ index }}"data-oldbuynum="{{ item.count }}"bindchange="changeBuyNum"/></view></view></view></view></van-cell-group><viewslot="right"class="van-swipe-cell__right"
+       bindtap="delCartGoods"
+       data-id="{{ item.goodsId }}">删除</view></van-swipe-cell><!-- 代码略 -->
</view>

➡️ /pages/cart/components/cart.wxml

// 导入接口 API 函数
import {reqCartList,reqUpdateChecked,reqCheckAllStatus,reqAddCart,
+   reqDelCartGoods
} from '@/api/cart'+ // 导入让删除滑块自动弹回的 behavior
+ import { swipeCellBehavior } from '@/behaviors/swipeCell'ComponentWithStore({// 注册 behavior
+   behaviors: [swipeCellBehavior, computedBehavior],// 组件的方法列表methods: {// coding...+   // 删除购物车中的商品
+   async delCartGoods(event) {
+     // 获取需要删除商品的 id
+     const { id } = event.currentTarget.dataset
+ 
+     // 询问用户是否删除该商品
+     const modalRes = await wx.modal({
+       content: '您确认删除该商品吗 ?'
+     })
+ 
+     if (modalRes) {
+       await reqDelCartGoods(id)
+ 
+       this.showTipGetList()
+     }
+   },+     onHide() {
+       // 在页面隐藏的时候,需要让删除滑块自动弹回
+       this.onSwipeCellCommonClick()
+     }}
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/711524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue ElementUI 修改消息提示框样式—messageBox 的大小

在窄屏模式下&#xff08;移动端或pda&#xff09;&#xff0c;提示框的宽度太宽&#xff0c;会出现显示不完全的问题。 应当如何修改 ElementUI 的样式呢&#xff1f; open() {this.$confirm(window.vm.$i18n.t("tips.conLogOut"),window.vm.$i18n.t("tips.tip…

11-Linux部署集群准备

Linux部署集群准备 介绍 在前面&#xff0c;我们所学习安装的软件&#xff0c;都是以单机模式运行的。 后续&#xff0c;我们将要学习大数据相关的软件部署&#xff0c;所以后续我们所安装的软件服务&#xff0c;大多数都是以集群化&#xff08;多台服务器共同工作&#xff…

【机器学习实战1】泰坦尼克号:灾难中的机器学习(一)数据预处理

&#x1f338;博主主页&#xff1a;釉色清风&#x1f338;文章专栏&#xff1a;机器学习实战&#x1f338;今日语录&#xff1a;不要一直责怪过去的自己&#xff0c;她曾经站在雾里也很迷茫。 &#x1f33c;实战项目简介 本次项目是kaggle上的一个入门比赛 &#xff1a;Titani…

锚索测力计数据处理与分析:MCU自动测量单元的应用

锚索测力计作为一种重要的工程监测工具&#xff0c;在桥梁、大坝、隧道等结构物的健康监测中发挥着日益重要的作用。如何高效、准确地处理和分析&#xff0c;锚索测力计所获取的数据成为了工程师们面临的重要问题。近年来&#xff0c;随着微控制器(MCU)技术的快速发展&#xff…

Python绘制实时空气质量地图

我们将使用 Google Colab 中的 Python 创建包含实时空气质量数据的交互式地图。 🌟简介 如果有人想查看地图上各个传感器的空气质量分布情况,以检查特定位置的空气质量数据,该怎么办?我接下来将解决这个问题。我们重点关注基于名为 PurpleAir 的密集空气质量网络来识别我们…

spring: HandlerInterceptor

文章目录 一、什么是HandlerInterceptor二、应用示例 一、什么是HandlerInterceptor HandlerInterceptor 是 Spring 框架中的一个接口&#xff0c;用于拦截处理程序执行。在 Spring MVC 中&#xff0c;你可以使用 HandlerInterceptor 来在处理程序执行前、执行后或渲染视图之前…

51-n皇后(回溯算法)

题目 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一…

前端开发项目必备神器之node工具整理

前言&#xff1a; 在我们开发项目中&#xff0c;node是我们必备的工具&#xff0c;在为了适应各种不同的开发需求的同时&#xff0c;node也有很多好用的插件提供给我们&#xff0c;这里整理个人的使用分享给大家&#xff01; 一、node相关 1、node官方网站&#xff0c;可以安装…

模拟算法题练习(二)(DNA序列修正、无尽的石头)

&#xff08;一、DNA序列修正&#xff09; 问题描述 在生物学中&#xff0c;DNA序列的相似性常被用来研究物种间的亲缘关系。现在我们有两条 DNA序列&#xff0c;每条序列由 A、C、G、T 四种字符组成&#xff0c;长度相同。但是现在我们记录的 DNA序列存在错误&#xff0c;为了…

ubuntu基础操作(1)-个人笔记

搜狗输入法Linux官网-首页搜狗输入法for linux—支持全拼、简拼、模糊音、云输入、皮肤、中英混输https://pinyin.sogou.com/linux 1.关闭sudo密码&#xff1a; 终端&#xff08;ctrl alt t&#xff09;输入 sudo visudo 打开visudo 找到 %sudo ALL(ALL:ALL) ALL 这一行…

羊大师分享,羊奶奶有哪些对健康有益的喝法?

羊大师分享&#xff0c;羊奶奶有哪些对健康有益的喝法&#xff1f; 羊奶奶有多种对健康有益的喝法&#xff0c;以下是一些建议&#xff1a; 直接饮用&#xff1a;将羊奶直接煮沸后饮用&#xff0c;可以保留羊奶中的营养成分&#xff0c;为身体提供全面的滋养。羊奶的丰富蛋白质…

代码随想录算法训练营第二十八天补|93.复原IP地址 ● 78.子集 ● 90.子集II

组合问题&#xff1a;集合内元素的组合&#xff0c;不同集合内元素的组合 分割问题&#xff1a;本质还是组合问题&#xff0c;注意一下如何分割字符串 回溯模板伪代码 void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择&#xff1a;本层集合中元素&#xf…

Softmax

Softmax函数是一种在机器学习和深度学习中广泛使用的激活函数&#xff0c;特别是在处理多分类问题时。它将一个含任意实数的向量转换成一个概率分布&#xff0c;其中每个元素的值代表了属于对应类别的概率。Softmax函数的输出是所有可能类别的概率分布&#xff0c;这些概率的总…

【六袆 - MySQL】MySQL 5.5及更高版本中,InnoDB是新表的默认存储引擎;

InnoDB 这是一个MySQL组件&#xff0c;结合了高性能和事务处理能力&#xff0c;以确保可靠性、健壮性和并发访问。它体现了ACID设计哲学。它作为一个存储引擎存在&#xff0c;处理使用ENGINEINNODB子句创建的或修改的表。请参阅第14章“InnoDB存储引擎”以获取有关架构细节和管…

【解决】虚幻导入FBX模型不是一个整体

问题&#xff1a; 现在有一个汽车的fbx模型&#xff0c;导入虚幻引擎&#xff0c;导入后变成了很多汽车零件模型。 解决&#xff1a; 把“合并网格体”勾选上&#xff0c;解决问题。

移动端app如何设计测试用例?

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、用户界面测试 布局和元素 验证所 有UI元素&#xff08;如…

C语言拼接字符串操作

代码解法不唯一&#xff0c;请在评论区留下你的实现方式和想法&#xff0c;我会将好的解法更新到文章中&#xff01;&#xff01; 要拼接 “字符串1” 和 “字符串2” &#xff0c;可以使用字符串连接操作。在C语言中&#xff0c;您可以使用strcat函数来将两个字符串连接起来。…

Unity 佳能SDK 及数据获取

1. 填写信息跟官方申请SDK,大概1-2个工作日会邮件回复你 佳能(中国)- 佳定制(佳能影像产品),SDK,EDSDK,CCAPI,软件开发包下载 2. 将SDK这两个文件放到 Unity Plugins文件夹 3. 把CameraControl 下面只要是绿色的 .cs 文件都复制到Unity 中

ElasticSearch搜索引擎使用指南

一、ES数据基础类型 1、数据类型 字符串 主要包括: text和keyword两种类型&#xff0c;keyword代表精确值不会参与分词&#xff0c;text类型的字符串会参与分词处理 数值 包括: long, integer, short, byte, double, float 布尔值 boolean 时间 date 数组 数组类型不…

基于ssm学生公寓管理系统的设计与开发论文

学生公寓管理系统的设计与实现 摘要 如今&#xff0c;科学技术的力量越来越强大&#xff0c;通过结合较为成熟的计算机技术&#xff0c;促进了学校、医疗、商城等许多行业领域的发展。为了顺应时代的变化&#xff0c;各行业结合互联网、人工智能等技术&#xff0c;纷纷开展了…