文章目录
1. 项目概述
在移动互联网时代,餐饮行业数字化转型已成为必然趋势。今天我想分享一个基于小程序的美食点餐/订餐系统的设计与实现,该系统包含用户模块、首页模块、分类模块、购物车模块和个人中心等核心功能模块。
2. 项目思维导图
3. 系统架构特点
- 纯前端实现:不依赖服务器,所有数据存储在本地
- 基于微信小程序API数据存储:主要使用wx.setStorageSync/wx.getStorageSync
- 数据持久化:关闭小程序后数据不会丢失
4. 核心模块实现代码
1. 登录注册
//用户注册
onRegisterHandle(){
if(this.data.username==='' || this.data.password ===''){
wx.showToast({
title: '注册信息不能为空',
icon :'error'
})
return
}
let users =wx.getStorageSync('users') ||[]
if(users.some(item => item.username === this.data.username)){
wx.showToast({
title: '用户名已存在',
icon: 'error'
})
return
}
let user ={
username: this.data.username,
password: this.data.password
}
users.push(user)
wx.setStorageSync("users",users)
wx.showToast({
title: '注册成功',
icon :'success'
})
setTimeout(() => {
wx.navigateBack()
},500)
}
//用户登录
onLoginHandle(options) {
if (this.data.username === '' || this.data.password === '') {
wx.showToast({
title: '登录信息不能为空',
icon: 'error'
})
return
}
let users = wx.getStorageSync('users') || []
if (users.some(item => item.username === this.data.username && item.password === this.data.password)) {
wx.showToast({
title: '登录成功',
icon: 'success'
})
let user = {
username: this.data.username,
password: this.data.password
}
//保存当前用户登录信息
wx.setStorageSync("user", user)
setTimeout(() => {
wx.navigateBack()
}, 500)
} else {
wx.showToast({
title: '用户名或密码错误',
icon: 'error'
})
}
},
2. 首页模块实现
//导入数据
import { bannerList, startList, produtList } from '../../utils/dataservice'
Page({
data: {
bannerList: [],
startList: [],
produtList: []
},
onLoad() {
this.setData({
//加载轮播图数据
bannerList: bannerList,
//加载精刚区数据
startList: startList,
//加载首页商品列表数据
produtList: produtList
})
},
/**
* 列表点击事件
*/
onItemClickHandle(options) {
const item = encodeURIComponent(JSON.stringify(options.currentTarget.dataset.item))
wx.navigateTo({
url: `/pages/detail/detail?productInfo=${item}`,
})
},
})
4. 分类模块实现
// pages/category/category.js
//导入数据
import getCategoryList from '../../utils/dataservice';
Page({
/**
* 页面的初始数据
*/
data: {
categoryList: [
{ "category_id": 0, "category_name": "新品推荐" },
{ "category_id": 1, "category_name": "招牌爆款" },
{ "category_id": 2, "category_name": "主厨推荐" },
{ "category_id": 3, "category_name": "开胃前菜" },
{ "category_id": 4, "category_name": "美味主食" },
{ "category_id": 5, "category_name": "美味甜品" },
{ "category_id": 6, "category_name": "鲜榨果品" },
{ "category_id": 7, "category_name": "蔬菜沙拉" },
{ "category_id": 8, "category_name": "轻食小吃" },
],
productList: [],
selectedIndex: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
//获取商品分类列表数据
this.getCategoryListData(this.data.selectedIndex)
},
/**
* 商品分类选择
*/
onSelectedHandle(options) {
this.setData({
selectedIndex: options.currentTarget.dataset.item.category_id
})
//获取商品分类列表数据
this.getCategoryListData(this.data.selectedIndex)
},
/**
* 获取商品分类列表数据
*/
getCategoryListData(selectedIndex) {
const result = getCategoryList(selectedIndex)
this.setData({
productList: result
})
},
/**
* 列表点击事件
*/
onItemClickHandle(options) {
const item = encodeURIComponent(JSON.stringify(options.currentTarget.dataset.item))
wx.navigateTo({
url: `/pages/detail/detail?productInfo=${item}`,
})
},
})
5. 购物车模块实现
// pages/cart/cart.js
Page({
/**
* 页面的初始数据
*/
data: {
carts: [],
totalPrice: 0
},
/**
* 生命周期函数--监听页面加载
*/
onShow(options) {
this.loadCartData();
},
/**
* 加载购物车数据
*/
loadCartData() {
const user = wx.getStorageSync('user') || {};
const allCarts = wx.getStorageSync('carts') || [];
// 提取当前用户的数据
const userCart = allCarts.find(cart => cart.username === user.username) || { items: [] };
this.setData({
carts: userCart.items,
totalPrice: this.calculateTotalPrice(userCart.items)
});
},
// 计算总价方法
calculateTotalPrice(cartItems) {
// 使用 reduce 方法累加每个商品的总价
return cartItems.reduce((total, item) => {
return total + (item.price * item.count);
}, 0).toFixed(2) * 100; // 保留两位小数
},
/**
* 加购
*/
plus(options) {
const user = wx.getStorageSync('user') || {};
const item = options.currentTarget.dataset.item;
// 1. 获取所有用户的购物车数据
const allCarts = wx.getStorageSync('carts') || [];
// 2. 找到当前用户的购物车(没有则初始化)
let userCart = allCarts.find(cart => cart.username === user.username);
if (!userCart) {
userCart = { username: user.username, items: [] };
allCarts.push(userCart);
}
// 3. 修改当前用户的购物车商品数量
const updatedItems = userCart.items.map(cartItem => {
return cartItem.product_id === item.product_id ? { ...cartItem, count: cartItem.count + 1 } : cartItem;
});
// 4. 更新数据
userCart.items = updatedItems;
wx.setStorageSync('carts', allCarts);
// 5. 更新页面显示(只展示当前用户的数据)
this.setData({
carts: updatedItems,
totalPrice: this.calculateTotalPrice(updatedItems)
});
},
// 更新购物车数据
updateCart(updatedCart) {
wx.setStorageSync('carts', updatedCart);
this.setData({
carts: updatedCart,
totalPrice: this.calculateTotalPrice(updatedCart)
});
},
/**
* 减购
*/
minus(options) {
// 获取当前点击商品数据
const product = options.currentTarget.dataset.item;
const allCarts = wx.getStorageSync('carts') || [];
const user = wx.getStorageSync('user');
// 1. 找到当前用户的购物车
const userCart = allCarts.find(cart => cart.username === user.username);
if (!userCart) return; // 无购物车则退出
// 2. 找到商品在购物车中的索引
const itemIndex = userCart.items.findIndex(item => item.product_id === product.product_id);
if (itemIndex === -1) return; // 商品不存在则退出
// 3. 减少数量
userCart.items[itemIndex].count -= 1;
// 4. 保存数据并更新 UI
wx.setStorageSync('carts', allCarts);
this.setData({
carts: userCart.items || [], // 确保空购物车时传空数组
totalPrice: this.calculateTotalPrice(userCart.items || [])
});
},
/**
* 删除商品
*/
removeItemHandle(options) {
// 获取要删除的商品
const product = options.currentTarget.dataset.item;
wx.showModal({
title: '温馨提示',
content: '确定要从购物车移除该商品吗?',
complete: (res) => {
if (res.confirm) {
const user = wx.getStorageSync('user');
const allCarts = wx.getStorageSync('carts') || [];
// 1. 找到当前用户的购物车
const userCartIndex = allCarts.findIndex(cart => cart.username === user.username);
if (userCartIndex === -1) return; // 用户购物车不存在则退出
// 2. 从该用户的 items 中移除目标商品
const updatedItems = allCarts[userCartIndex].items.filter(item => item.product_id !== product.product_id);
// 3. 更新数据
allCarts[userCartIndex].items = updatedItems;
// 4. 保存数据并更新 UI
wx.setStorageSync('carts', allCarts);
this.setData({
carts: updatedItems, // 更新当前页面的购物车列表
totalPrice: this.calculateTotalPrice(updatedItems)
});
}
}
})
},
/**
* 提交订单
*/
onSubmit(options) {
const user = wx.getStorageSync('user')
if (!user) {
wx.showModal({
title: '温馨提示',
content: '系统检测到您未登录,请先登录',
complete: (res) => {
if (res.confirm) {
wx.navigateTo({
url: '/pages/login/login',
})
}
}
})
return;
}
if (this.data.totalPrice === 0) {
wx.showToast({
title: '购物车空空如也,去看看吧~',
icon: 'error',
success: () => {
setTimeout(() => {
wx.switchTab({
url: '/pages/category/category',
})
}, 500)
}
})
return;
}
wx.showModal({
title: '温馨提示',
content: '您确定下单吗?',
complete: (res) => {
if (res.confirm) {
// 1. 获取当前用户的购物车数据
const allCarts = wx.getStorageSync('carts') || [];
const userCartIndex = allCarts.findIndex(cart => cart.username === user.username);
if (userCartIndex === -1 || allCarts[userCartIndex].items.length === 0) {
wx.showToast({ title: '购物车为空', icon: 'error' });
return;
}
const userCartItems = allCarts[userCartIndex].items;
// 2. 生成订单(添加订单时间、状态等元信息)
const newOrder = {
order_id: Date.now().toString(), // 简单生成订单ID(实际项目建议更严谨的方式)
username: user.username,
items: userCartItems,
create_time: new Date().toLocaleString(),
status: '支付成功'
}
// 3. 保存订单(多用户订单隔离)
const allOrders = wx.getStorageSync('orders') || [];
allOrders.push(newOrder); // 将新订单追加到订单列表
wx.setStorageSync('orders', allOrders);
// 4. 清空当前用户的购物车(不影响其他用户)
allCarts[userCartIndex].items = []; // 清空items而非删除用户条目,保留用户购物车结构
wx.setStorageSync('carts', allCarts);
// 5. 更新页面状态
this.setData({
carts: [],
totalPrice: 0
});
wx.showToast({
title: '下单成功',
})
}
}
})
}
})
6. 订单模块实现
// pages/order/order.js
Page({
/**
* 页面的初始数据
*/
data: {
orderList: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.loadUserOrders();
},
/**
* 订单加载方法中预处理数据
*/
loadUserOrders() {
const { username } = wx.getStorageSync('user');
// 1. 获取所有订单(假设数据结构为订单数组,每个订单包含items)
const result = wx.getStorageSync('orders') || [];
//2. 过滤出当前用户的订单,并平铺items
const userOrder = result
.filter(item => item.username === username)
.flatMap(order => {
// 为每个商品添加订单元信息(可选)
return order.items.map(item => ({
...item,
order_id: order.order_id, // 关联订单ID
order_status: order.status, // 订单状态
create_time: order.create_time, // 下单时间
unique_id: `${order.order_id}${item.product_id}`
}));
})
// 3. 更新数据
this.setData({
orderList: userOrder
})
},
/**
* 删除订单
*/
removeOrderHandle(options) {
const orderInfo = options.currentTarget.dataset.item;
const user = wx.getStorageSync('user')
wx.showModal({
title: '温馨提示',
content: '确定要从订单中删除该商品吗?',
complete: (res) => {
if (res.confirm) {
// 1. 获取所有订单数据
const allOrders = wx.getStorageSync('orders') || [];
// 2. 遍历查找目标商品
const updatedOrders = allOrders.map(order => {
// 2.1 检查订单归属
if (order.username !== user.username) {
return order;
}
// 2.2 过滤掉目标商品
const updatedItems = order.items.filter(item => `${order.order_id}${item.product_id}` !== orderInfo.unique_id)
// 2.3 updatedItems 可能返回空items的订单,所有加判空处理
return updatedItems.length > 0 ? { ...order, items: updatedItems } : null;
})
.filter(Boolean) // 移除null(即空订单)
console.log(updatedOrders)
// 4. 保存数据
wx.setStorageSync('orders', updatedOrders);
// 5. 重新加载
this.loadUserOrders();
wx.showToast({
title: '删除成功',
})
}
}
})
}
})
5. 注意事项
- 存储限制:wx.setStorageSync有10MB大小限制
- 多设备同步:本地存储无法实现多设备同步
- 数据持久性:用户清理缓存会丢失所有数据
这个纯前端实现方案适合作为学习项目或个人小店使用,如果要开发商业应用,建议还是使用后端数据库存储数据。
6. 项目效果截图
7. 关于作者其它项目视频教程介绍
本人在b站录制的一些视频教程项目,免费供大家学习
- Android新闻资讯app实战:https://www.bilibili.com/video/BV1CA1vYoEad/?vd_source=984bb03f768809c7d33f20179343d8c8
- Androidstudio开发购物商城实战:https://www.bilibili.com/video/BV1PjHfeXE8U/?vd_source=984bb03f768809c7d33f20179343d8c8
- Android开发备忘录记事本实战:https://www.bilibili.com/video/BV1FJ4m1u76G?vd_source=984bb03f768809c7d33f20179343d8c8&spm_id_from=333.788.videopod.sections
- Androidstudio底部导航栏实现:https://www.bilibili.com/video/BV1XB4y1d7et/?spm_id_from=333.337.search-card.all.click&vd_source=984bb03f768809c7d33f20179343d8c8
- Android使用TabLayout+ViewPager2实现左右滑动切换:https://www.bilibili.com/video/BV1Mz4y1c7eX/?spm_id_from=333.337.search-card.all.click&vd_source=984bb03f768809c7d33f20179343d8c8