资讯动态

微信小程序餐饮点餐外卖源码拆包与二次开发实战指南

发布时间:2026/10/17 7:43:24 来源:尧图企业网站定制
简介这份资源是面向餐饮行业开发者与小程序学习者的微信小程序点餐外卖源码基于微信开发者工具与 WXML、WXSS、JavaScript 技术栈实现覆盖在线点餐、外卖配送、叫号排队、微信支付、用户与订单管理、数据统计分析等模块适合希望快速搭建餐饮小程序或研究完整业务闭环的初中级开发者。压缩包共 521 个文件以 137 个 js 业务逻辑脚本、108 个 wxss 样式表、104 个 json 配置、102 个 wxml 页面结构为主另有 44 个 wxs 脚本及少量图片与说明文档整体约 833KB目录结构清晰便于按模块检索与二次开发。目前已有 2331 人学习下载。读者可从中获得一套可直接运行的点餐外卖项目骨架参考菜品展示、购物车、订单状态流转、支付验证与后台管理等实现思路并在此基础上按自身需求定制功能。1. 餐饮点餐小程序源码拆包从“能跑”到“敢改”的第一道坎上个月帮一个做餐饮 SaaS 的朋友看他们新接手的点餐小程序对方团队交接时只丢过来一个压缩包和一句“开箱即用”。结果本地跑起来首页白屏控制台报app.json里tabBar路径找不到文件。翻回去看目录发现pages/menu被改成了pages/menuList但配置文件没同步。这种“开箱即用”的源码包真正卡人的从来不是功能多复杂而是交接文档缺失导致的配置漂移。这份微信小程序餐饮点餐外卖源码核心就是一套完整的点餐商城闭环菜单浏览、购物车、下单、订单状态流转外加外卖配送地址管理。它适合两类人一是想快速搭一个点餐 Demo 验证业务逻辑的开发者二是需要一套可二次开发底座的接单团队。但前提是你得先搞清楚它的目录约定和配置入口在哪否则“开箱”变“开箱即翻车”。2. 目录结构与配置入口先找到“总闸”再谈改代码2.1 小程序源码的四个核心目录拿到压缩包解压后根目录通常长这样app.js、app.json、app.wxss三个全局文件打头下面挂pages、components、utils、images四个文件夹。app.json是整个小程序的“总闸”里面pages数组决定哪些页面被注册tabBar决定底部导航栏长什么样window决定顶部导航栏颜色和标题。很多新手改代码第一步就去翻pages/index/index.js结果改了半天没生效原因是页面根本没在app.json里注册或者注册路径和实际文件夹名大小写不一致。微信开发者工具在 Windows 上对路径大小写不敏感但真机预览时 iOS 是敏感的Pages/Menu和pages/menu在开发者工具里都能跑上传体验版就白屏。我一般拿到新包先做一件事把app.json里的pages数组和实际目录做一次逐项比对用脚本跑一遍最快。// check-pages.js 放在项目根目录用 node 跑 const fs require(fs); const path require(path); const appJson JSON.parse(fs.readFileSync(./app.json, utf8)); appJson.pages.forEach(pagePath { // 小程序页面由 .js .json .wxml .wxss 四个文件组成至少要有 .js 和 .wxml const base path.join(__dirname, pagePath); const missing [.js, .wxml].filter(ext !fs.existsSync(base ext)); if (missing.length) { console.log(缺失文件: ${pagePath} - ${missing.join(, )}); } else { console.log(OK: ${pagePath}); } });这段脚本的逻辑很直白读app.json的pages数组逐个检查每个页面路径下.js和.wxml是否存在。参数说明pagePath是app.json里写的路径不带扩展名base拼出绝对路径missing收集缺失的扩展名。跑完如果输出全是 OK说明页面注册没问题如果有缺失先补文件再谈其他。常见做法是把这个脚本挂在package.json的predev钩子里每次启动前自动跑一遍省得手动查。2.2 点餐商城的页面流转与数据流向餐饮点餐商城的页面流转一般是首页pages/index/index展示菜品分类和推荐菜点击分类跳到菜单页pages/menu/menu菜单页左侧是分类锚点、右侧是菜品列表加购后购物车数据存在app.globalData.cart或通过wx.setStorageSync持久化。下单页pages/order/order读取购物车数据提交后生成订单记录订单列表页pages/orderList/orderList展示历史订单。外卖场景还会多一个地址管理页pages/address/address。数据流向的核心是购物车状态管理加购、减购、清空、计算总价这四个操作如果分散在各个页面里各写一套后期改需求就是灾难。我一般会抽一个utils/cart.js统一管理页面只负责调用和渲染。// utils/cart.js 购物车统一管理 const CART_KEY cart_list; function getCart() { return wx.getStorageSync(CART_KEY) || []; } function addToCart(item) { const cart getCart(); const exist cart.find(i i.id item.id); if (exist) { exist.count 1; } else { cart.push({ ...item, count: 1 }); } wx.setStorageSync(CART_KEY, cart); return cart; } function removeFromCart(id) { let cart getCart(); cart cart.filter(i i.id ! id); wx.setStorageSync(CART_KEY, cart); return cart; } function getTotal(cart) { return cart.reduce((sum, i) sum i.price * i.count, 0); } module.exports { getCart, addToCart, removeFromCart, getTotal };逻辑说明getCart从本地缓存读购物车数组读不到返回空数组addToCart先查是否已存在同 id 菜品存在则数量加一不存在则新增一条并设数量为 1removeFromCart按 id 过滤掉整条记录getTotal用reduce累加price * count。参数说明item至少包含id、name、price三个字段price单位是元浮点数计算总价时如果对精度敏感建议在getTotal里先乘 100 转整数再除回去。这个模块的好处是页面里不用再写wx.getStorageSync和wx.setStorageSync改存储键名或换存储方案只动一个文件。2.3 外卖配送与堂食模式的配置切换餐饮点餐小程序通常要同时支持堂食和外卖两种模式。堂食模式下下单时不需要填地址直接选桌号外卖模式下必须选收货地址可能还要算配送费。源码里一般会在app.globalData里放一个orderMode字段或者在首页加一个切换按钮。我见过一种做法是在app.js的onLaunch里根据wx.getStorageSync(orderMode)决定默认模式用户切换时写回缓存。这里有个坑如果切换模式后没有清空购物车堂食加购的菜品带到外卖模式里配送费计算会出错。常见做法是切换模式时弹窗提示“切换后将清空购物车”确认后调removeFromCart清空。参数上配送费一般按距离或固定金额算源码里如果没写距离计算通常是在utils/下留了一个delivery.js占位里面用固定配送费加起送价门槛改起来不难。3. 从源码到可运行编译、调试与真机预览的完整链路3.1 开发者工具导入与编译配置拿到源码包后第一步是用微信开发者工具导入项目。导入时要注意三个参数项目目录选解压后的根目录有app.json的那一层AppID 如果源码里写的是测试号可以选“测试号”或填自己的 AppID项目名称随意。导入后工具会自动编译如果报app.json解析错误大概率是 JSON 里有注释或尾逗号微信小程序的 JSON 文件不支持注释也不支持尾逗号。编译成功后模拟器里应该能看到首页如果白屏但控制台没报错检查app.json的pages数组第一项是不是首页路径小程序默认加载pages数组的第一项作为启动页。我一般会把启动页显式写在第一位避免顺序错乱导致启动页不对。{ pages: [ pages/index/index, pages/menu/menu, pages/order/order, pages/orderList/orderList, pages/address/address ], window: { navigationBarBackgroundColor: #ffffff, navigationBarTitleText: 点餐, navigationBarTextStyle: black }, tabBar: { list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/orderList/orderList, text: 订单 } ] } }这段配置里pages第一项是启动页tabBar的list至少两项才能显示底部导航。参数说明navigationBarBackgroundColor只支持十六进制颜色不支持rgb()tabBar的pagePath必须在pages数组里注册过否则工具会报错。如果源码里tabBar用了自定义组件custom: true那底部导航的渲染逻辑就在components/tabBar/里改文字和图标要去组件里改改app.json没用。3.2 模拟器调试与真机预览的差异排查模拟器跑通不代表真机没问题。最常见的差异有三个一是网络请求模拟器里wx.request不校验域名真机预览时如果请求的接口域名没在微信公众平台配置合法域名会直接失败二是本地缓存模拟器清缓存方便真机缓存可能残留旧数据导致页面状态不对三是样式模拟器默认 iPhone 6/7/8 尺寸真机屏幕比例不同rpx单位在大部分情况下能自适应但固定px的间距在大屏上会显得偏小。我一般会在真机预览前做两件事把wx.request的url换成https://开头的合法域名或本地开发工具代理然后在app.js的onLaunch里加一行wx.clearStorageSync()临时清缓存确认没问题后再去掉。如果真机预览时页面卡顿检查setData的数据量点餐菜单页如果一次性把几百个菜品全setData进去低端机上会明显掉帧常见做法是分页加载或虚拟列表。3.3 订单状态流转的本地模拟与接口对接源码包如果没带后端订单状态流转通常是本地模拟的下单后往wx.setStorageSync(order_list)里塞一条记录状态字段status初始为pending订单列表页根据status渲染不同文案。对接真实后端时需要把本地存储换成wx.request调接口这里的关键是订单状态字段的映射。常见做法是后端返回status数字码前端用一个映射表转成文案。// utils/orderStatus.js 订单状态映射 const STATUS_MAP { 0: 待支付, 1: 已支付, 2: 配送中, 3: 已完成, 4: 已取消 }; function getStatusText(code) { return STATUS_MAP[code] || 未知状态; } module.exports { getStatusText };逻辑说明STATUS_MAP是数字码到文案的映射getStatusText接收后端返回的code返回对应文案查不到返回“未知状态”。参数说明数字码的具体含义要和后端约定好源码里如果用的是字符串状态如pending对接时要么改前端映射要么让后端适配。我一般会在接口文档里把状态码表贴出来前后端各留一份避免后期状态对不上。4. 避坑与排查点餐小程序源码最常见的五个翻车点4.1 页面白屏但控制台无报错现象编译成功模拟器白屏控制台干净。原因app.json的pages数组第一项路径写错或者首页.wxml里根节点用了view但样式里写了display: none。解决先确认pages第一项和实际目录一致再检查首页.wxss里有没有全局隐藏样式最后看app.js的onLaunch里有没有同步报错被try/catch吞掉。4.2 购物车数量角标不更新现象加购后购物车图标上的数字不变。原因角标数字存在app.globalData里但页面没有监听变化setData没触发。解决把角标数字也存到本地缓存页面onShow时重新读取并setData或者用wx.setTabBarBadge直接设置 tabBar 角标这个 API 会自动更新。4.3 下单后订单列表不显示新订单现象下单成功跳转到订单列表列表里没有刚下的单。原因下单页写缓存用的键名和订单列表页读缓存用的键名不一致比如一个用orderList一个用order_list。解决把存储键名抽到utils/constants.js里统一导出所有页面引用同一个常量。4.4 真机预览时图片不显示现象模拟器里菜品图片正常真机预览裂图。原因图片路径用了本地绝对路径或http://开头的网络图真机不支持http且本地路径在真机上解析规则不同。解决本地图片放images/目录用相对路径引用网络图换成https://并确认域名已配置。4.5 支付流程调不起来现象点击支付按钮没反应或报错requestPayment:fail。原因源码里支付逻辑用的是模拟支付直接改订单状态对接真实微信支付需要后端统一下单返回prepay_id等参数前端wx.requestPayment的参数不完整。解决先确认源码里支付是模拟还是真实模拟支付改状态即可真实支付需要后端配合前端参数缺一不可。5. 二次开发进阶把点餐源码改成多门店系统的三个关键改动5.1 多门店数据隔离与门店切换单门店源码改成多门店核心改动在数据层。原来菜品列表直接从utils/menu.js读静态数组现在要按门店 id 请求不同菜单。我一般会在app.globalData里加shopId字段首页加门店选择入口选择后写缓存并刷新菜单页。菜单页onLoad时读shopId请求对应门店的菜品接口。这里有个细节购物车也要按门店隔离否则 A 店加购的菜带到 B 店结算价格和库存都对不上。常见做法是购物车存储键名带上shopId如cart_${shopId}切换门店时读对应键。// utils/cart.js 多门店版本改造 const CART_KEY_PREFIX cart_; function getCartKey(shopId) { return CART_KEY_PREFIX shopId; } function getCart(shopId) { return wx.getStorageSync(getCartKey(shopId)) || []; } function addToCart(shopId, item) { const cart getCart(shopId); const exist cart.find(i i.id item.id); if (exist) { exist.count 1; } else { cart.push({ ...item, count: 1 }); } wx.setStorageSync(getCartKey(shopId), cart); return cart; } module.exports { getCart, addToCart };逻辑说明getCartKey把门店 id 拼进存储键getCart和addToCart都多了一个shopId参数。参数说明shopId从app.globalData.shopId或页面参数传入确保同一门店的购物车数据互不干扰。改动量不大但调用处都要补上shopId漏一个就会出现跨店数据串。5.2 菜品规格与加料选项的扩展餐饮点餐里菜品常有规格大份/小份和加料加辣/加蛋单门店源码如果只支持固定价格扩展时要在菜品数据结构里加specs和addons数组。加购时把选中的规格和加料拼成一个唯一skuId购物车里按skuId去重而不是按菜品id。这个改动会影响购物车、下单、订单详情三个页面建议先改数据结构再改渲染逻辑最后改价格计算。价格计算时规格加价和加料加价要累加到基础价上getTotal里不能再简单用price * count。5.3 订单状态与后厨打印的对接思路多门店场景下订单提交后要通知对应门店的后厨。源码里如果没带打印对接常见做法是订单提交成功后调一个云函数或后端接口后端再通过局域网推给后厨打印机。前端这边只需要在订单提交成功后把shopId和订单详情传给后端剩下的不用管。验证方法在订单列表页加一个“模拟后厨接单”按钮点击后把订单状态从已支付改成配送中确认状态流转和页面刷新正常。我一般会在改完多门店后用两个不同门店各下一单然后切门店看订单列表是否隔离购物车是否各自独立这两个场景跑通基本就没大问题了。从那以后我每次拿到“开箱即用”的源码包都强制先跑一遍页面注册检查脚本再清一次缓存真机预览省得后面返工。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑