微信小程序实战案例 - 餐馆点餐系统 阶段 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 } = dishif (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.dishcart.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 集合,实现真正的下单流程。

继续加油,愉快编码!

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

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

相关文章

从红黑树到哈希表:原理对比与典型场景应用解析(分布式以及布隆过滤器)

在数据结构的世界里&#xff0c;红黑树一直以「自平衡二叉查找树」的身份备受赞誉。凭借红黑节点的精妙设计&#xff0c;它能将插入、删除、查找的时间复杂度稳定控制在 ( log ⁡ n ) (\log n) (logn)&#xff0c;成为处理有序数据的经典方案。然而&#xff0c;当业务场景对「…

游戏报错?MFC140.dll怎么安装才能解决问题?提供多种MFC140.dll丢失修复方案

MFC140.dll 是 Microsoft Visual C 2015 运行库的重要组成部分&#xff0c;许多软件和游戏依赖它才能正常运行。如果你的电脑提示 "MFC140.dll 丢失" 或 "MFC140.dll 未找到"&#xff0c;说明系统缺少该文件&#xff0c;导致程序无法启动。本文将详细介绍 …

《电子类专业:通往科技未来的钥匙》

一、电子类专业全景概览 在当今科技飞速发展的时代,电子类专业无疑占据着现代科技体系中基础与核心的重要地位。从我们日常生活中不可或缺的智能手机、电脑,到推动社会进步的人工智能、大数据技术,再到探索宇宙奥秘的航天航空设备,电子类专业的身影无处不在。它就像一把万…

Java--批量删除

前端部分 前端代码主要负责收集用户选择的学生记录的 id&#xff0c;并将这些 id 发送给后端的 DeleteMoreServlet 进行处理。 批量删除按钮绑定点击事件 $(".deleteMore").on("click",function(){// ... }); 当用户点击 “批量删除” 按钮时&#xff…

2025年4月份生活有感

今天在5000B培训的下午&#xff0c;一起入所来的小伙伴&#xff0c;有个申请了深圳大学的博士&#xff0c;已录取。哎&#xff0c;想起了当年申博时候信心和决心不足&#xff0c;导致后面匆匆的拿了offer去工作。看到同事的选择还是非常羡慕&#xff0c;想到自己5月份的婚礼&am…

数学建模学习资料免费分享:历年赛题与优秀论文、算法课程、数学软件等

本文介绍并分享自己当初准备数学建模比赛时&#xff0c;收集的所有资料&#xff0c;包括历年赛题与论文、排版模板、算法讲解课程与书籍、评分标准、数学建模软件等各类资料。 最近&#xff0c;准备将自己在学习过程中&#xff0c;到处收集到的各类资料都整理一下&#xff0c;并…

关于 微服务负载均衡 的详细说明,涵盖主流框架/解决方案的对比、核心功能、配置示例及总结表格

以下是关于 微服务负载均衡 的详细说明&#xff0c;涵盖主流框架/解决方案的对比、核心功能、配置示例及总结表格&#xff1a; 1. 负载均衡的核心概念 负载均衡在微服务中用于将请求分发到多个服务实例&#xff0c;以实现&#xff1a; 高可用性&#xff1a;避免单点故障。性…

个人博客搭建过程

尝试博客搭建,前面注册部分很简单&#xff0c;就不写了&#xff0c;以我看到的一个博客为基础&#xff0c;加上我自己的测试结束 1.官网 https://dash.infinityfree.com 前半部分参考&#xff1a; 使用Infinityfree免费虚拟主机搭建一个wordpress网站 2.创建账户或登录您的…

Proxmox VE 网络配置命令大全

如果对 Proxmox VE 全栈管理感兴趣&#xff0c;可以关注“Proxmox VE 全栈管理”专栏&#xff0c;后续文章将围绕该体系&#xff0c;从多个维度深入展开。 概要&#xff1a;Proxmox VE 网络配置灵活&#xff0c;满足虚拟化组网需求。基础靠桥接实现虚拟机与物理网络互联&#x…

【QT入门到晋级】QT打动态库包及引入动态库包

前言 本篇为持续更新状态&#xff0c;内容包含window、Linux下打动态库包&#xff0c;以及引入动态库包的方式。 一、window 1、动态库打包 以百度的OCR接口调用打dll库为例&#xff0c;以下为qtcreator创建动态库过程&#xff1a; 1.1Qtcreator创建lib项目 创建成功后&…

Uniapp: 大纲

目录 一、基础巩固1.1、Uniapp:下拉选择框ba-tree-picker1.2、Uniapp&#xff1a;确认框1.3、Uniapp&#xff1a;消息提示框1.4、Uniapp&#xff1a;列表提示框1.5、Uniapp&#xff1a;获取当前定位坐标 二、项目配置2.1、Uniapp&#xff1a;修改端口号2.2、Uniapp&#xff1a;…

WPF 从Main()方法启动

1.去掉App.xaml StartupUri“MainWindow.xaml” 只会让App.g.cs 不生成这行代码&#xff0c;但是还是会生成的App.g.cs文件中生成Main方法 this.StartupUri new System.Uri("MainWindow.xaml", System.UriKind.Relative);默认的App.xaml的生成操作是 应用程序定义…

ADB的安装及抓取日志(2)

三、ADB抓取日志 在使用ADB抓取日志前&#xff0c;首先要保证电脑已经安装并配置ADB&#xff0c;在上一节已经验证完成。连接设备&#xff1a;可通过USB或者WI-FI&#xff0c;将安卓设备与电脑连接&#xff0c;并启用USB调试模式&#xff0c;此处我选择的是通过电脑与安卓设备…

opencv 灰度实验

opencv 灰度实验 1. 最大值法2. 平均值法3. 加权均值法4(直接读取灰度图)cv2.IMREAD_GRAYSCALE5内置将原图转换为灰度图cv2.cvtColor()6 两个极端的灰度值 灰度图与彩色图最大的不同就是&#xff1a;彩色图是由R、G、B三个通道组成&#xff0c;而灰度图只有一个通道&#xff0c…

『Kubernetes(K8S) 入门进阶实战』实战入门 - Pod 详解

『Kubernetes(K8S) 入门进阶实战』实战入门 - Pod 详解 Pod 结构 每个 Pod 中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类 用户程序所在的容器&#xff0c;数量可多可少Pause 容器&#xff0c;这是每个 Pod 都会有的一个根容器&#xff0c;它的作用有两个 可…

用 Vue 3 实现一个拖拽排序表格组件(支持列/行重排、列宽调整)

文章目录 一、项目初始化1.1 技术栈说明1.2 项目结构图&#xff08;Mermaid&#xff09; 二、构建基础表格组件2.1 创建基本表格结构 三、实现行拖拽排序3.1 安装依赖3.2 使用 vuedraggable 实现拖拽 四、实现列宽拖拽调整4.1 基本样式设置4.2 添加拖拽逻辑 五、实现列拖拽排序…

Python异常处理全面指南

目录 一、异常处理概述 1.1 什么是异常&#xff1f; 1.2 常见异常类型示例 二、基础异常捕获 2.1 简单异常捕获语法 2.2 特定异常类型捕获 三、高级异常处理技术 3.1 完整异常处理语法 3.2 异常传递机制 四、主动抛出异常 4.1 自定义异常抛出 4.2 创建自定义异常类 …

基于混沌映射的LDPC信道编译码matlab性能仿真,对比LDPC

目录 1.算法仿真效果 2.算法涉及理论知识概要 2.1 混沌映射 2.2 基于混沌映射的LDPC编译码 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操…

学点概率论,打破认识误区

概率论是统计分析和机器学习的核心。掌握概率论对于理解和开发稳健的模型至关重要&#xff0c;因为数据科学家需要掌握概率论。本博客将带您了解概率论中的关键概念&#xff0c;从集合论的基础知识到高级贝叶斯推理&#xff0c;并提供详细的解释和实际示例。 目录 简介 基本集合…

【数据结构_9】栈和队列

队列 Queue 一个方向进&#xff0c;一个方向出 Queue队列提供的核心方法&#xff1a; 入队列&#xff1a;offer add 出队列&#xff1a;poll remove 取队首元素&#xff1a; peek element 前面一列发生错误是返回null 后面一列发生错误时抛出异常 Queue是否能够使用isEm…