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

微信小程序实战案例 - 餐馆点餐系统 阶段 2 – 购物车

阶段 2 – 购物车(超详细版)

目标

  1. 把“加入购物车”做成 全局状态,任何页面都能读写
  2. 在本地 持久化(关闭小程序后购物车仍在)
  3. 新建 购物车页:数量增减、总价实时计算、去结算入口
  4. 打 Git Tag v2.0‑cart

1. 学到的核心技术

技术/概念关键 API/组件为什么要学
全局状态App.globalData / 简易 store.js小项目先不引入第三方状态库,足够用
本地持久化wx.setStorageSync / wx.getStorageSync保证用户切后台、重进小程序后数据不丢
UI 组件(弹出购物车)
 (底部结算条)
 (数量加减)
快速完成电商式交互
TabBar Badgewx.setTabBarBadge在底部“购物车”图标上显示件数

2. 项目结构新增

miniprogram/
  ├─ store/          # 新增
  │   └─ cart.js
  ├─ pages/
  │   ├─ index/      # 首页已存在
  │   └─ cart/       # 新建购物车页面

3. 编写轻量级全局 Store

路径miniprogram/store/cart.js

const CART_KEY = 'CART_V1'
const store = {
  data: { items: {} },

  load() {
    this.data.items = wx.getStorageSync(CART_KEY) || {}
  },
  save() {
    wx.setStorageSync(CART_KEY, this.data.items)
  },
  add(dish) {
    const { _id } = dish
    if (this.data.items[_id]) {
      this.data.items[_id].count += 1
    } else {
      this.data.items[_id] = { ...dish, count: 1 }
    }
    this.save()
  },
  totalCount() {
    return Object.values(this.data.items).reduce((s, i) => s + i.count, 0)
  },
  totalPrice() {
    return Object.values(this.data.items)
      .reduce((s, i) => s + i.count * i.price, 0)
      .toFixed(2)
  }
  
}
module.exports = store


4. 在 app.js 中加载购物车

// miniprogram/app.js
App({
  onLaunch() {
    const cart = require('./store/cart')
    cart.load()
    this.globalData = { cart }
  }
})

5. 修改首页:加入购物车 & 更新角标

文件pages/index/index.js

只需要把之前的 onAddCart 改成:

import cart from '../../store/cart'

onAddCart(e) {
    const dish = e.currentTarget.dataset.dish
    cart.add(dish)
    wx.setTabBarBadge({ index: 1, text: String(cart.totalCount()) })
    wx.showToast({ title: '已加入购物车', icon: 'success' })
  }
}

提示:在 app.jsontabBar 数组里,把第二项页面路径设成 "pages/cart/index",这样角标才会显示在购物车图标上。


6. 新建购物车页面

6.1 组件声明 pages/cart/index.json
{
  "navigationBarTitleText": "购物车"
}
6.2 页面布局 index.wxml
<view class="page">
  <block wx:for="{{list}}" wx:key="_id">
    <view class="cart-item">
      <image class="thumb" src="{{item.img}}" mode="aspectFill" />
      <view class="info">
        <text class="name">{{item.name}}</text>
        <text class="price">¥{{item.price}}</text>
        <text class="count">x {{item.count}}</text>
      </view>
    </view>
  </block>

  <view class="bottom-bar">
    <text>共 {{totalCount}} 件</text>
    <text>合计:¥{{totalPrice}}</text>
    <button type="primary" bindtap="onCheckout">去结算</button>
  </view>
</view>

6.3 页面逻辑 index.js
const cart = require('../../store/cart')

Page({
  data: {
    list: [],
    totalCount: 0,
    totalPrice: '0.00'
  },

  onShow() {
    cart.load()
    this.refresh()
  },

  refresh() {
    const items = Object.values(cart.data.items)
    const totalCount = cart.totalCount()
    const totalPrice = cart.totalPrice()

    this.setData({
      list: items,
      totalCount,
      totalPrice
    })
  },

  onCheckout() {
    if (!this.data.totalCount) {
      wx.showToast({ title: '购物车为空', icon: 'none' })
      return
    }
    wx.navigateTo({ url: '/pages/confirm/index' }) // 下一阶段页
  }
})


6.4 简单样式 index.wxss
.page {
  padding: 20rpx;
}

.cart-item {
  display: flex;
  background: #fff;
  padding: 20rpx;
  margin-bottom: 20rpx;
  border-radius: 16rpx;
  box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
}

.thumb {
  width: 100rpx;
  height: 100rpx;
  border-radius: 8rpx;
  margin-right: 20rpx;
}

.info {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}

.name {
  font-weight: bold;
  font-size: 32rpx;
}

.price {
  color: #fa541c;
}

.count {
  font-size: 28rpx;
  color: #888;
}

.bottom-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  background: #fff;
  padding: 20rpx;
  display: flex;
  justify-content: space-between;
  box-shadow: 0 -2rpx 12rpx rgba(0,0,0,0.1);
}


7. TabBar 配置示例

// app.json(节选)
"tabBar": {
    "list": [
      { "pagePath": "pages/index/index", "text": "菜单", "iconPath": "images/icons/home.png", "selectedIconPath": "images/icons/home-active.png" },
      { "pagePath": "pages/cart/index",  "text": "购物车", "iconPath": "images/icons/business.png", "selectedIconPath": "images/icons/business-active.png" }
    ]
  }

在这里插入图片描述

8. 自测清单 & Git Tag

  1. 首页点两道菜 → 角标显示 2
  2. 进入购物车页
    • 看得到两条记录
  3. 关闭小程序再打开 → 数据依旧存在
  4. 一切通过后:
git add .
git commit -m "feat: shopping cart"
git tag v2.0-cart
git push --tags

9. 练习(进阶挑战)

难度练习内容
cart.js 增加 clear() 方法,在购物车页提供“一键清空”。
⭐⭐在首页卡片上显示当前已选数量(小圆角徽标)。
⭐⭐⭐把 Store 升级为 PiniaRemax Recoil,体验响应式自动刷新。

阶段小结

  • 你已拥有 加入购物车 → 全局状态 → 本地持久化 → 购物车 UI 的完整链路。
  • 代码量 ≈ 250 行,但逻辑清晰、易维护。
  • 接下来进入 阶段 3 – 下单 & 云数据库:把购物车内容写入 orders 集合,实现真正的下单流程。

继续加油,愉快编码!

相关文章:

  • 嵌入式常见概念的介绍
  • C++ 重构muduo网络库
  • FPGA 37 ,FPGA千兆以太网设计实战:RGMII接口时序实现全解析( RGMII接口时序设计,RGMII~GMII,GMII~RGMII 接口转换 )
  • 微信小程序跳4
  • RT-2论文深度解读:视觉-语言-动作统一模型的机器人泛化革命
  • AI NAS:当网络存储与人工智能深度融合的技术路径与未来展望
  • nvm使用手册
  • java零基础教学笔记
  • 02核心-EffectSpec,EffectContext
  • RV1106 OCR 识别算法
  • 代码随想录算法训练营day3(链表)
  • 流与分组的共生关系
  • vue + uniapp 实现仿百度地图/高德地图/美团/支付宝 滑动面板 纯css 实现
  • Matlab个性化绘图第10期—滑珠进度柱状图
  • 富文本编辑器的内容导出html,并保留图片
  • 【第41节】windows的中断与异常及异常处理方式
  • 【第四十周】文献阅读:用于检索-增强大语言模型的查询与重写
  • 精品整理 | 云安全知识证书 (CCSK) v5 备考学习资源汇总
  • Reinforcement Learning-Autonomous car-useful
  • 【数学建模】(智能优化算法)粒子群优化算法(PSO)详解与Python实现
  • 时隔三年,俄乌直接谈判重启
  • 特朗普公开“怼”库克:苹果不应在印度生产手机
  • 中国进出口银行:1-4月投放制造业中长期贷款超1800亿元
  • 会谈时间迟迟未定、核心议题存在分歧,俄乌“土耳其谈判”一波三折
  • “家国万里时光故事会” 举行,多家庭共话家风与家国情怀
  • 丰富“互换通”产品类型,促进中国金融市场高水平对外开放