【愚公系列】2022年10月 微信小程序-电商项目-商品购物车功能实现


前言

在电商的核心交易流程中,购物车是其中非常重要的一环,它承担商品加购、价格计算、促销活动展示等功能,与会员系统、商品系统、库存系统、订单系统等紧密结合。

vant-weapp的GoodsAction商品导航api

GoodsAction Props

参数 说明 类型 默认值
safe-area-inset-bottom 是否为 iPhoneX 留出底部安全距离 boolean true

GoodsActionIcon Props

参数 说明 类型 默认值
text 按钮文字 string -
icon 图标类型,可选值见icon组件 string -
info 图标右上角提示信息 string/number -
url 点击后跳转的链接地址 string -
link-type 链接跳转类型,可选值为 redirectTo switchTab reLaunch string navigateTo
id 标识符 string -
disabled 是否禁用按钮 boolean false
loading 是否显示为加载状态 boolean false
open-type 微信开放能力,具体支持可参考 微信官方文档 string -
app-parameter 打开 APP 时,向 APP 传递的参数 string -
lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文 string en
session-from 会话来源 string -
send-message-title 会话内消息卡片标题 string 当前标题
send-message-path 会话内消息卡片点击跳转小程序路径 string 当前分享路径
send-message-img sendMessageImg string 截图
show-message-card 显示会话内消息卡片 string false
class-prefix v1.10.1 类名前缀 string van-icon

GoodsActionButton Props

参数 说明 类型 默认值
text 按钮文字 string -
color 按钮颜色,支持传入 linear-gradient 渐变色 string -
url 点击后跳转的链接地址 string -
link-type 链接跳转类型,可选值为 redirectTo switchTab reLaunch string navigateTo
id 标识符 string -
type 按钮类型,可选值为 primary warning danger string danger
plain 是否为朴素按钮 boolean false
size 按钮尺寸,可选值为 normal large small mini string normal
disabled 是否禁用按钮 boolean false
loading 是否显示为加载状态 boolean false
open-type 微信开放能力,具体支持可参考 微信官方文档 string -
app-parameter 打开 APP 时,向 APP 传递的参数 string -
lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文 string en
session-from 会话来源 string -
send-message-title 会话内消息卡片标题 string 当前标题
send-message-path 会话内消息卡片点击跳转小程序路径 string 当前分享路径
send-message-img sendMessageImg string 截图
show-message-card 显示会话内消息卡片 string false

Events

事件名 说明 参数
bind:click 按钮点击事件回调 -

GoodsActionIcon Slot

名称 说明
icon 自定义图标

GoodsActionButton Slot

名称 说明
/ 按钮显示内容

GoodsActionIcon 外部样式类

类名 说明
icon-class 图标样式类
text-class 文字样式类

GoodsActionButton 外部样式类

类名 说明
custom-class 根节点样式类

一、商品购物车功能实现

// miniprogram/pages/cart/index.js

Page({
    
    
  /**
   * 页面的初始数据
   */
  data: {
    
    
    showLoginPanel:false,
    cartIdSelectedResult:[],
    allIsSelected:false,
    editMode:false,
    carts:[],
    totalPrice:0
  },
  // 重新计算总价
  calcTotalPrice(){
    
    
    let totalPrice = 0
    let ids = this.data.cartIdSelectedResult
    let carts = this.data.carts
    ids.forEach(id=>{
    
    
      carts.some(item=>{
    
    
        if (item.id == id){
    
    
          totalPrice += item.price * item.num 
          return true 
        }
        return false
      })
    })
    this.setData({
    
    
      totalPrice
    })
  },
  //改变编辑模式
  changeEditMode(){
    
    
    let editMode = !this.data.editMode
    this.setData({
    
    
      editMode
    })
  },

  onSelectGoodsItem(e){
    
    
    let cartIdSelectedResult = e.detail
    this.setData({
    
    
      cartIdSelectedResult,
    });
    this.calcTotalPrice()
  },
  onSelectAll(event) {
    
    
    let allIsSelected = event.detail
    let cartIdSelectedResult = this.data.cartIdSelectedResult
    cartIdSelectedResult.length = 0

    if (allIsSelected){
    
    
      let carts = this.data.carts
      for(let j=0;j<carts.length;j++){
    
    
        cartIdSelectedResult.push(`${
    
    carts[j].id}`)
      }
    }

    this.setData({
    
    
      allIsSelected,
      cartIdSelectedResult
    });
    this.calcTotalPrice()
  },

  /**
   * 页面显示的时候去加载数据
   */
  async onShow(){
    
    
    let res = await getApp().wxp.request4({
    
    
      url:'http://localhost:3000/user/my/carts',
      method:'get'
    })
    if (res.data.msg == "ok"){
    
    
      let carts = res.data.data 
      this.setData({
    
    
        carts
      })
    }
  },

  onCartConfirm(e){
    
    
    // 拿到列表数据
    let carts = this.data.carts 
    let cartData = []
    let ids = this.data.cartIdSelectedResult
    if (ids.length == 0){
    
    
      wx.showModal({
    
    
        title: '未选择商品',
        showCancel: false
      })
      return
    }
    ids.forEach(id=>{
    
    
      carts.some(item=>{
    
    
        if (item.id == id){
    
    
          cartData.push(Object.assign({
    
    }, item))
          return true 
        }
        return false
      })
    })
    wx.navigateTo({
    
    
      url: `/pages/confirm-order/index`,
      success: function(res) {
    
    
        res.eventChannel.emit('cartData', {
    
     data: cartData })
      }
    })
  },

  async onCartGoodsNumChanged(e){
    
    
    let cartGoodsId = e.currentTarget.dataset.id 
    let oldNum = parseInt( e.currentTarget.dataset.num )
    // console.log('e.detail', typeof e.detail, cartGoodsId, oldNum)
    let num = e.detail
    let data = {
    
    num}

    let res = await getApp().wxp.request4({
    
    
      url:`http://localhost:3000/user/my/carts/${
    
    cartGoodsId}`,
      method:'put',
      data 
    })
    if (res.data.msg == 'ok'){
    
    
      wx.showToast({
    
    
        title: num > oldNum ? '增加成功' : '减少成功',
      })
      // 修复数据
      let carts = this.data.carts
      carts.some(item=>{
    
    
        if (item.id == cartGoodsId){
    
    
          item.num = num 
          return true 
        }
        return false
      })
      this.calcTotalPrice()
    }
  },

  async removeCartGoods(e){
    
    
    let ids = this.data.cartIdSelectedResult
    if (ids.length == 0){
    
    
      wx.showModal({
    
    
        title: '没有选择商品',
        showCancel: false
      })
      return 
    }
    let data = {
    
    ids}
    let res = await getApp().wxp.request4({
    
    
      url:'http://localhost:3000/user/my/carts',
      method:'delete',
      data
    })
    if (res.data.msg == 'ok'){
    
    
      let carts = this.data.carts
      for(let j=0;j<ids.length;j++){
    
    
        let id = ids[j]
        carts.some((item,index)=>{
    
    
          if (item.id == id){
    
    
            carts.splice(index,1)
            return true 
          }
          return false 
        })
      }
      this.setData({
    
    
        carts
      })
    }
  },
})
{
    
    
  "usingComponents": {
    
    
    "van-cell": "@vant/weapp/cell/index",
    "van-cell-group": "@vant/weapp/cell-group/index",
    "van-button": "@vant/weapp/button/index",
    "van-card": "@vant/weapp/card/index",
    "van-stepper": "@vant/weapp/stepper/index",
    "van-submit-bar": "@vant/weapp/submit-bar/index",
    "van-checkbox": "@vant/weapp/checkbox/index",
    "van-checkbox-group": "@vant/weapp/checkbox-group/index",
    "LoginPanel": "../../components/login"
  }
}
<!--miniprogram/pages/cart/index.wxml-->
<!-- <text>miniprogram/pages/cart/index.wxml</text> -->

<van-cell-group>
	<van-cell title="购物车" value="" label="" border="{
    
    { false }}">
		<van-button bindtap="changeEditMode" slot="right-icon" plain type="info" size="mini">{
    
    {
    
    editMode?'完成':'编辑'}}</van-button>
	</van-cell>
</van-cell-group>

<block wx:for="{
    
    {carts}}" wx:key="id">
<van-checkbox-group value="{
    
    { cartIdSelectedResult }}" bind:change="onSelectGoodsItem">
	<view class="goods-card-container">
		<view style="width:30px;display:flex;align-items:center;justify-content:center;">
			<van-checkbox icon-size="17px" shape="square" name="{
    
    {item.id}}"></van-checkbox>
		</view>
		<view style="flex:1;background:white;">
			<van-card custom-class="goods-card" price="{
    
    {item.price*item.num/100}}元" desc="{
    
    {item.sku_desc}}" title="{
    
    {item.goods_name}}" thumb="{
    
    {item.goods_image}}">
				<view slot="footer">
					<van-stepper data-num="{
    
    {item.num}}" data-id="{
    
    {item.id}}" bind:change="onCartGoodsNumChanged" value="{
    
    {item.num}}" step="1" />
				</view>
			</van-card>
		</view>
	</view>
</van-checkbox-group>
</block>

<van-submit-bar bind:submit="onCartConfirm" wx:if="{
    
    {!editMode}}" price="{
    
    { totalPrice }}" button-text="提交订单">
	<van-checkbox value="{
    
    { allIsSelected }}" bind:change="onSelectAll" shape="square">全选</van-checkbox>
	<view wx:if="{
    
    {false}}" slot="tip">您的收货地址</view>
</van-submit-bar>

<van-cell-group wx:else title="" style="position: fixed;bottom: 0;left: 0;width: 100%;">
	<van-cell>
		<view slot="title">
			<van-checkbox value="{
    
    { allIsSelected }}" bind:change="onSelectAll" shape="square" name="all">
				全选
			</van-checkbox>
		</view>
		<van-button bindtap="removeCartGoods" size="mini" slot="right-icon" plain type="info">删除</van-button>
	</van-cell>
</van-cell-group>

<LoginPanel show="{
    
    {showLoginPanel}}"></LoginPanel>
/* miniprogram/pages/cart/index.wxss */
.goods-card{
    
    
  background-color: #fefefe !important;
}
.goods-card-container {
    
    
  display:flex;margin:10px;background:#fefefe;
}

.goods-card-container + .goods-card-container{
    
    
  padding-top: 10px;
}

二、效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/127178357