微信小程序开发实战 / 综合项目——点餐系统(下)
1
教学目标
  • 掌握购物车的状态管理与交互
  • 理解订单的完整流程
  • 能够完成点餐系统全部功能
  • 案例:案例6 点餐系统(下)
2
重点、难点与课时分配
教学重点

购物车、订单、个人中心开发

教学难点

购物车状态管理、订单流程

课时分配(共 3 学时)

理论 0.5 学时
实践 2.5 学时

以项目实战为主,仅用 0.5 学时讲订单流程要点

3
课件要点

购物车功能

添加商品: 点击加购按钮, 数量+1
数量修改: 加减按钮控制商品数量
全选/取消全选: 复选框联动
合计金额: 实时计算选中商品总价
删除商品: 左滑删除或长按删除
购物车数据: 本地缓存 vs 全局状态

订单功能

确认订单: 展示选中商品、金额、备注
收货地址: wx.chooseAddress 获取微信地址
提交订单: 调用后端接口创建订单
订单列表: 按状态分类(待付款/待收货/已完成)
订单详情: 展示订单完整信息

个人中心

用户信息: 头像/昵称展示
我的订单: 快捷入口(待付款/待收货/退款/全部)
收货地址管理: 增删改查
设置页面: 关于/清除缓存/退出登录
登录态管理: token存储与过期处理

项目优化与总结

性能优化: setData优化、图片懒加载、分包加载
体验优化: 骨架屏、加载动画、空状态
代码规范: ESLint、命名规范、注释
测试: 功能测试、兼容性测试
发布: 体验版 → 审核版 → 线上版
4
代码示例与讲解

购物车功能

cart.js 购物车效果
1// 购物车核心逻辑 cart.js
2const app = getApp()
3
4Page({
5 data: { cartList: [], totalPrice: 0, totalCount: 0, isAllChecked: true },
6
7 onShow() {
8 this.refreshCart()
9 },
10
11 // 刷新购物车数据
12 refreshCart() {
13 const cartList = app.globalData.cartList
14 const totalPrice = cartList.reduce((sum, item) => {
15 return item.checked ? sum + item.price * item.count : sum
16 }, 0)
17 const totalCount = cartList.reduce((sum, item) => {
18 return item.checked ? sum + item.count : sum
19 }, 0)
20 this.setData({ cartList, totalPrice, totalCount })
21 },
22
23 // 添加商品(菜单页调用)
24 addToCart(dish) {
25 const cartList = app.globalData.cartList
26 const exist = cartList.find(item => item.id === dish.id)
27 if (exist) {
28 exist.count++ // 已存在则数量+1
29 } else {
30 cartList.push({ ...dish, count: 1, checked: true })
31 }
32 this.refreshCart()
33 },
34
35 // 数量增减
36 changeCount(e) {
37 const { id, type } = e.currentTarget.dataset
38 const item = app.globalData.cartList.find(i => i.id === id)
39 if (type === 'add') item.count++
40 if (type === 'minus') {
41 if (item.count <= 1) {
42 this.removeItem(id); return
43 }
44 item.count--
45 }
46 this.refreshCart()
47 },
48
49 // 删除商品
50 removeItem(id) {
51 app.globalData.cartList = app.globalData.cartList.filter(i => i.id !== id)
52 this.refreshCart()
53 },
54
55 // 全选/取消全选
56 toggleAllCheck() {
57 const isAllChecked = !this.data.isAllChecked
58 app.globalData.cartList.forEach(item => item.checked = isAllChecked)
59 this.refreshCart()
60 }
61})
购物车核心逻辑:数据存在 app.globalData.cartList 全局共享。addToCart 添加商品时先 find 查找是否已存在,存在则 count++,不存在则 push 新项。changeCount 数量增减,减到1再减则 removeItem 删除。refreshCartreduce 计算选中商品总价和总数,全选按钮 toggleAllCheck 切换所有商品 checked 状态。页面 onShow 时刷新数据。

订单功能

order.js 订单确认页效果
1// 订单确认页 order.js
2const app = getApp()
3import { createOrder } from '../../api/order'
4
5Page({
6 data: {
7 checkedItems: [], totalPrice: 0,
8 address: null, remark: ''
9 },
10
11 onLoad() {
12 // 筛选选中商品
13 const checkedItems = app.globalData.cartList.filter(item => item.checked)
14 const totalPrice = checkedItems.reduce((sum, i) => sum + i.price * i.count, 0)
15 this.setData({ checkedItems, totalPrice })
16 },
17
18 // 选择收货地址
19 chooseAddress() {
20 wx.chooseAddress({
21 success: (res) => {
22 this.setData({ address: res })
23 // res包含: userName, telNumber, provinceName...
24 }
25 })
26 },
27
28 // 提交订单
29 submitOrder() {
30 if (!this.data.address) {
31 return wx.showToast({ title: '请选择地址', icon: 'none' })
32 }
33 wx.showLoading({ title: '提交中...' })
34 createOrder({
35 items: this.data.checkedItems.map(i => ({
36 dishId: i.id, count: i.count, price: i.price
37 })),
38 address: this.data.address,
39 totalPrice: this.data.totalPrice,
40 remark: this.data.remark
41 }).then(res => {
42 wx.hideLoading()
43 // 清除已下单的购物车商品
44 app.globalData.cartList = app.globalData.cartList.filter(i => !i.checked)
45 wx.navigateTo({ url: '/pages/orderSuccess/orderSuccess?id=' + res.data.orderId })
46 }).catch(() => {
47 wx.hideLoading()
48 })
49 }
50})
51
52// ⚠️ 订单要点
53// 1. chooseAddress 需用户授权
54// 2. 提交前校验地址和商品
55// 3. 下单成功后清除已选购物车项
56// 4. 防重复提交:提交时禁用按钮
订单确认页:onLoad 时 filter 筛选购物车中 checked 的商品,reduce 计算总价。wx.chooseAddress 调用微信地址选择器,返回 userName、telNumber、provinceName 等字段,需用户授权。submitOrder 提交订单前校验地址,showLoading 防止重复点击,调用 createOrder API 提交,成功后清除已下单的购物车商品并跳转成功页。注意防重复提交需在提交时禁用按钮。

个人中心

mine.js 个人中心效果
1// 个人中心 mine.js
2const app = getApp()
3
4Page({
5 data: {
6 userInfo: null,
7 orderStats: { pending: 0, paid: 0, done: 0 }
8 },
9
10 onShow() {
11 this.refreshUserInfo()
12 this.loadOrderStats()
13 },
14
15 // 登录/刷新用户信息
16 refreshUserInfo() {
17 const userInfo = app.globalData.userInfo
18 if (userInfo) {
19 this.setData({ userInfo })
20 }
21 },
22
23 // 登录操作
24 handleLogin() {
25 wx.login({ success: (res) => {
26 wx.getUserProfile({
27 desc: '用于完善会员资料',
28 success: (profileRes) => {
29 app.globalData.userInfo = profileRes.userInfo
30 this.setData({ userInfo: profileRes.userInfo })
31 }
32 })
33 }})
34 },
35
36 // 加载订单统计
37 loadOrderStats() {
38 getOrderStats().then(res => {
39 this.setData({ orderStats: res.data })
40 })
41 },
42
43 // 订单快捷入口
44 goToOrders(e) {
45 const tab = e.currentTarget.dataset.tab
46 wx.navigateTo({ url: `/pages/orderList/orderList?tab=${tab}` })
47 },
48
49 // 地址管理
50 goToAddress() {
51 wx.navigateTo({ url: '/pages/addressList/addressList' })
52 }
53})
54
55<!-- mine.wxml 关键结构 -->
56<view class="user-card" wx:if="{{userInfo}}">
57 <image src="{{userInfo.avatarUrl}}" class="avatar"/>
58 <text>{{userInfo.nickName}}</text>
59</view>
60<view class="login-btn" wx:else bindtap="handleLogin">
61 点击登录
62</view>
个人中心页面:顶部用户卡片,未登录显示 登录按钮,已登录显示头像和昵称。登录用 wx.login + getUserProfile 获取信息存入 globalData。中部订单快捷入口,显示待付款、待配送、已完成数量,点击跳转对应订单列表。下部功能菜单包括 收货地址管理、联系客服、设置等。页面 onShow 时刷新用户信息和订单统计数据。

项目优化与总结

optimization.js 优化与发布流程
1// 1. 骨架屏优化首屏体验
2<!-- skeleton.wxml -->
3<view wx:if="{{loading}}">
4 <view class="skeleton-banner"></view>
5 <view class="skeleton-rect"></view>
6 <view class="skeleton-circle"></view>
7</view>
8<view wx:else>...真实内容...</view>
9
10/* 骨架屏样式 */
11.skeleton-banner { background: #f0f0f0; height: 360rpx; }
12.skeleton-rect { background: #f0f0f0; height: 40rpx; margin: 20rpx; border-radius: 8rpx; }
13
14// 2. setData 性能优化
15// ❌ 频繁调用 setData
16this.setData({ name: 'A' })
17this.setData({ age: 20 })
18// ✅ 合并调用
19this.setData({ name: 'A', age: 20 })
20
21// ❌ 传递大量不需要的数据
22this.setData({ list: hugeArray })
23// ✅ 只更新变化的部分
24this.setData({ 'list[0].count': 2 })
25
26// 3. 图片优化
27// 使用 mode="aspectFill" 避免变形
28// 使用 lazy-load 懒加载
29<image mode="aspectFill" lazy-load />
30
31// 4. 代码规范
32// • 统一命名:页面小写,组件驼峰
33// • 公共逻辑提取到 utils
34// • 请求统一走 request.js 封装
35// • 及时清除定时器和监听器
36
37// 5. 发布流程
38// ① 上传代码 → ② 提交审核 → ③ 发布上线
39// 开发版 → 体验版 → 审核版 → 线上版
项目优化要点:骨架屏 在数据加载前显示灰色占位元素,提升首屏感知速度;setData 优化——合并多次调用为一次,只更新变化的数据路径如 'list[0].count' 而非整个数组;图片优化用 aspectFill 防变形、lazy-load 懒加载。代码规范:统一命名、公共逻辑提取 utils、请求统一走封装。发布流程:上传代码→体验版测试→提交审核→发布上线。
6
课堂视频
第14次课 · 综合项目——点餐系统(下)
本次课教学视频请在课堂现场观看 视频文件较大未随本站发布;如需回看,请向任课教师索取或在课程群下载。
7
教材案例源码
用微信开发者工具「导入项目」打开对应目录即可运行。知识储备是分知识点的最小示例,案例实现项目实现是完整工程,服务器端是案例配套的后端接口服务。
【案例6】综合项目 点餐系统
教材配套源码 · 2 个工程:项目实现 / 服务器端
8
课后实践
基础
完成购物车功能

实现购物车的商品增删、数量修改、总价计算功能

进阶
完成订单管理

实现订单提交、订单列表、订单详情功能,完成多页面数据同步

挑战
完整联调与优化

完成点餐系统所有功能联调,优化用户体验(加载状态、空状态提示、错误处理)

9
本课小结
购物车功能
订单功能
个人中心
项目优化与总结