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

购物车

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

思路分析:

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

落地代码:

js 复制代码
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 属性,控制弹框的隐藏和展示

html 复制代码
<!-- 商品的底部商品导航 -->
<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 属性,来区分是进行的某种操作

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

  // 加入购物车
  handleAddcart() {
    this.setData({
      show: true,
+       buyNow: 0
    })
  },

  // 立即购买
  handeGotoBuy() {
    this.setData({
      show: true,
+       buyNow: 1
    })
  },

    
  // 代码略...
})

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

思路分析:

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

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

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

落地代码:

➡️ /behaviors/userBehavior.js

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

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

html 复制代码
<van-stepper
  value="{{ count }}"
+  integer
+  min="1"
+  max="200"
  bind:change="onChangeGoodsCount"
/>

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

js 复制代码
// 监听是否更改了购买数量
onChangeGoodsCount(event) {
  // 将最新的购买数量同步到 data
  this.setData({
    count: Number(event.detail)
  })
},

// 弹框的确定按钮
async handleSubmit() {
 // 解构获取数据
 const { token, count, blessing, buyNow } = this.data
 const 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

javascript 复制代码
Page({
    
  data: {
    // coding...
+     allCount: '' // 购物车商品总数量
  },
    
      // 弹框的确定按钮
  async handleSubmit() {
    // 如果没有 token ,让用户新登录
    if (!this.data.token) {
      wx.navigateTo({
        url: '/pages/login/login'
      })

      return
    }

    // 解构获取数据
    const { count, blessing, allCount } = this.data
    const 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

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

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

html 复制代码
<view>
  <view
    wx: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-checkbox
                checked-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

html 复制代码
<van-checkbox
  checked-color="#FA4126"
+   value="{{ item.isChecked }}"
+   bind:change="updateChecked"
+   data-id="{{ item.goodsId }}"
+   data-index="{{ index }}"
></van-checkbox>

➡️ /pages/cart/cart.js

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
      // 获取商品的索引和 id
      const { 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

cmd 复制代码
# 安装并构建 框架拓展 computed
npm i miniprogram-computed

实现步骤:

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

落地代码:

➡️ /pages/cart/cart.js

js 复制代码
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'
import { reqCartList, reqUpdateChecked } from '@/api/cart'

+ const computedBehavior = require('miniprogram-computed').behavior

ComponentWithStore({
    
+   // 注册计算属性
+   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

html 复制代码
<!-- 底部工具栏 -->
<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

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

➡️ /pages/cart/cart.js

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. 购物车-更新商品购买数量思路分析

思路分析:

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

差值的计算公式:

shell 复制代码
差值 = 新值 - 旧值

例如:

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,还原为之前的购买数量
js 复制代码
const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/

实现步骤:

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

落地代码:

➡️ /pages/cart/cart.wxml

html 复制代码
<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

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

js 复制代码
// 从 miniprogram-licia 导入防抖函数
import { debounce } from 'miniprogram-licia'

// 更新购买的数量
+ changeBuyNum: debounce(async function (event) {
+   // 代码略...
+ }, 500)

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

思路分析:

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

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

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

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

实现步骤:

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

落地代码:

➡️ /pages/cart/cart.wxml

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

➡️ /pages/cart/cart.js

js 复制代码
ComponentWithStore({
    
  // coding...
    
  // 定义计算属性
  computed: {

    // coding...

    // 计算商品价格总和
    totalPrice(data) {
      let totalPrice = 0

      data.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

html 复制代码
+  <view bindtap="onSwipeCellPage">
    
  <!-- 代码略 -->
    
  <van-swipe-cell
    class="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-checkbox
            checked-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-stepper
                min="1"
                max="200"
                integer
                value="{{ item.count }}"
                data-id="{{ item.goodsId }}"
                data-index="{{ index }}"
                data-oldbuynum="{{ item.count }}"
                bindchange="changeBuyNum"
              />
            </view>
          </view>
        </view>
      </view>
    </van-cell-group>
    <view
      slot="right"
      class="van-swipe-cell__right"
+       bindtap="delCartGoods"
+       data-id="{{ item.goodsId }}"
    >
      删除
    </view>
  </van-swipe-cell>
    
    
  <!-- 代码略 -->
</view>

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

js 复制代码
// 导入接口 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()
+     }
  }
})
相关推荐
丁总学Java31 分钟前
页面、组件、应用、生命周期(微信小程序)
微信小程序·小程序·生命周期
编程千纸鹤5 小时前
高校宿舍信息管理系统小程序
小程序·宿舍管理小程序
说私域6 小时前
基于开源 AI 智能名片 S2B2C 商城小程序的视频号交易小程序优化研究
人工智能·小程序·零售
丁总学Java18 小时前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
说私域19 小时前
基于开源 AI 智能名片、S2B2C 商城小程序的用户获取成本优化分析
人工智能·小程序
mosen86819 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq229511650220 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
尚梦1 天前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
小飞哥liac1 天前
微信小程序的组件
微信小程序
stormjun1 天前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享