简介:这是一份用于学习微信小程序开发的完整美食菜谱项目源码,适合初、中级开发者以及想快速上手小程序实战的学员。压缩包内共四十九个文件,以页面逻辑脚本、界面结构描述、样式表和配置文件为主,并配有大量菜谱与界面图片,整体约四百六十三KB,结构清晰,便于直接导入开发者工具运行。项目包含全局配置、页面路由、工具函数以及菜谱列表、详情、搜索、用户等典型模块,完整覆盖从启动加载、页面跳转到菜品数据渲染的流程。已有五百二十二人学习,对于想模仿完整项目或二次开发的人来说,是一份轻量但内容全面的参考资源。通过研读代码,可以理解页面数据绑定、事件处理、本地存储等常用微信小程序开发技巧,并在此基础上快速扩展自己的美食或工具类应用。
1. 美食菜谱微信小程序不是模板,是需求的最小闭环
拿到一个「美食菜谱微信小程序.rar」,多数人第一反应是解压、导入开发者工具、看页面跑起来。但一个菜谱类小程序源码包的价值,不在于它长得像大众点评或下厨房,而在于它把「找菜谱、看步骤、做收藏、搜关键词」这条主链路完整地走了一遍。对这四件事的处理方式,几乎决定了小程序后续是做内容展示还是做社区互动。
这篇内容适合两类人:一是刚接触微信小程序、想用真实项目实例理解页面与数据流的新手;二是产品经理或独立开发者,需要快速评估一套菜谱小程序的代码结构,判断哪些部分能复用、哪些部分必须重写。后面的内容会按照「拿到源码包之后怎么处理和调整」的顺序展开,从目录结构、数据绑定,一直讲到加载体验和搜索收录,中间涉及的关键代码都能直接复制改参数。
2. 从 .rar 到可运行:解压、导入与 AppID 配置
2.1 解压前先做目录审查,避免中文路径和嵌套目录
.rar压缩包在 Windows 上常用 WinRAR 或 7-Zip 解压,macOS 上可以用 The Unarchiver。解压前建议先看一下压缩包内顶层目录,很多源码包存在双重嵌套,解压出来是美食菜谱微信小程序/美食菜谱微信小程序/,导入时容易选错层级。
另一个高频坑是解压路径中的中文和空格。微信开发者工具对中文路径能处理,但 node_modules 目录和上传代码时偶尔会出现编码异常。我一般的做法是解压到纯英文路径,例如D:\projects\recipe-miniapp,等确认能跑之后再移动位置。
解压完成后,确认根目录下有app.js、app.json、app.wxss这三个文件,说明是原生微信小程序项目;如果看到的是src目录或者manifest.json、pages.json,说明是 uniapp 项目,那需要改用 HBuilderX 打开或者用 CLI 方式编译,不能直接用开发者工具导入。
2.2 project.config.json 与 appid:最容易卡住的三个配置项
打开微信开发者工具,选择「导入项目」,指向解压后的目录。此时工具会读取project.config.json,但有三个地方几乎每次都要手动调整。
{ "appid": "touristappid", "projectname": "recipe-miniapp", "setting": { "es6": true, "minified": true, "urlCheck": false } }appid填touristappid是游客模式,可以预览但无法请求真实接口、无法上传。有自己小程序账号的,改成自己的 AppID;没有的话,在公众平台注册个人类型小程序即可,个人主体也能覆盖菜谱这类工具型场景。
urlCheck设为false表示关闭域名校验。本地调试阶段,如果请求了http://接口,这个配置可以避免报「不在合法域名列表」。但注意上线前必须改回true,并且把接口域名配置到服务器域名白名单里。
es6转 ES5 建议保持开启,真机上 Android 低版本 WebView 对 ES6 语法支持不完整,这个选项能减少兼容性报错。
2.3 导入后第一眼看 app.json:页面注册和窗口外观
app.json是全局配置,菜谱类小程序常见的结构如下:
{ "pages": [ "pages/index/index", "pages/detail/detail", "pages/category/category", "pages/favorite/favorite", "pages/mine/mine" ], "window": { "navigationBarBackgroundColor": "#ff6348", "navigationBarTitleText": "每日菜谱", "navigationBarTextStyle": "white", "backgroundColor": "#f5f5f5" }, "tabBar": { "color": "#999999", "selectedColor": "#ff6348", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/category/category", "text": "分类" }, { "pagePath": "pages/favorite/favorite", "text": "收藏" }, { "pagePath": "pages/mine/mine", "text": "我的" } ] } }pages数组第一项是启动页,菜谱类通常是首页列表。navigationBarTitleText是顶部导航栏文字,也就是用户肉眼看到的标题;navigationBarBackgroundColor可以按菜谱品牌色调整,关键在于navigationBarTextStyle只有black和white两个值,深色背景配白字、浅色背景配黑字,这点很容易被忽略。
tabBar 的list最多支持 5 项,菜谱类 4 个 tab 足够。图标不配置也能跑,只是底部只显示文字;如果需要图标,iconPath建议用 81px * 81px 的 png,文件大小限制 40kb,超过会编译报错。
3. 菜谱小程序的核心页面与数据模型
3.1 页面四件套与 tabBar 结构
每个微信小程序页面由.wxml、.wxss、.js、.json四个文件组成。.wxml负责结构,.wxss负责样式,.js负责数据和交互,.json负责页面级配置,例如标题和下拉刷新。
菜谱小程序最少需要五个页面:首页做推荐列表,分类页做菜系和场景筛选,详情页展示步骤,收藏页存本地,个人页做设置。首页和分类页的流量占比最高,开发优先级也最高。
这里有一个常见误区:很多人把详情页也加到 tabBar 里,导致用户点进一道菜之后底部导航还停留在「首页」。详情页是典型的下钻页面,不应该出现在 tabBar 中。
3.2 用本地 JSON 模拟菜谱数据,不急着连后端
大多数菜谱源码包默认的数据源是本地 JSON 文件,这一设计有实际考虑:菜谱数据以读为主、更新频率低,且图片和步骤文字相对固定,前期用本地静态数据完全够用。
把数据放在utils/data.js,导出数组供页面引用:
const recipes = [ { id: 1, name: "红烧肉", category: "热菜", time: 90, difficulty: "中等", cover: "/assets/images/recipes/hongshaorou.png", ingredients: [ { name: "五花肉", amount: "500g" }, { name: "冰糖", amount: "20g" }, { name: "生抽", amount: "2勺" } ], steps: [ "五花肉切块,冷水下锅焯水去浮沫", "锅中放少许油,下冰糖炒出糖色", "放入肉块翻炒上色,加生抽、料酒", "加热水没过肉块,小火炖 60 分钟", "大火收汁,出锅装盘" ] } ]; module.exports = { recipes };字段设计上,id必须唯一,详情页跳转依赖它;ingredients用数组嵌套,是因为每道菜的食材数量不同;steps保持数组顺序,对应制作步骤先后。图片路径cover使用绝对路径,以/开头,和页面相对路径区分开。
如果后期要接入真实后端,这个数据结构可以直接映射到数据库表,recipes集合的文档结构不需要改动。
3.3 列表渲染用 wx:for,详情页传参靠 url 拼接
首页 wxml 中渲染菜谱卡片:
<view class="recipe-card" wx:for="{{recipeList}}" wx:key="id" bindtap="goDetail">goDetail(e) { const id = e.currentTarget.dataset.id; wx.navigateTo({ url: `/pages/detail/detail?id=${id}` }); }wx.navigateTo会保留当前页面栈,跳转后用户能通过左上角返回。不要用wx.redirectTo,它关闭当前页面,用户从详情页返回时直接回到 tab 页,体验断层。详情页在onLoad(options)中接收参数:
onLoad(options) { const id = Number(options.id); const detail = recipes.find(item => item.id === id); this.setData({ detail }); }options.id是字符串,本地数据里的id是数字,不做Number()转换的话find永远匹配不到。这个类型陷阱在从 url 提取参数时很常见,值得养成随手转换的习惯。
4. 搜索、收藏与图文混排:把「能用」改成「好用」
4.1 搜索框用防抖处理,空态给明确提示
菜谱搜索本质是对本地数组进行filter过滤,但输入过程中的每次bindinput都会触发一次 setData,如果后续接的是后端接口,每敲一个字就发一次请求,会导致接口压力大、页面卡顿。常见的做法是加 300ms 防抖。
onSearchInput(e) { const keyword = e.detail.value; if (this.searchTimer) { clearTimeout(this.searchTimer); } this.searchTimer = setTimeout(() => { const result = recipes.filter(item => item.name.includes(keyword) || item.category.includes(keyword) ); this.setData({ recipeList: result }); }, 300); }includes是字符串匹配方法,比indexOf !== -1可读性好,在开发者工具基础库 2.x 以上都支持。这里搜索维度覆盖菜名name和分类category,如果要增加食材搜索,需要把ingredients数组map成字符串再做匹配。
搜索结果为空时,不能白屏。加一个wx:if="{{recipeList.length === 0}}"的提示块,文案「没有找到相关菜谱,换个关键词试试」,配合重新置空的搜索按钮,体验才算完整。
4.2 收藏功能用 wx.setStorageSync 还是云开发?
收藏是菜谱类小程序的高频操作,两条技术路线各有适用场景。
本地存储用wx.setStorageSync,数据存在用户设备上,读写快、无需联网,但换设备不同步。适合个人工具型小程序,或者没有服务器资源、想先跑通 MVP 的场景。云开发用数据库集合,用户收藏写入云端,支持多端同步,适合后续做用户体系、内容社区,但需要开通云环境并处理登录态。
本地存储的收藏实现:
toggleFavorite() { const detail = this.data.detail; const favorites = wx.getStorageSync('favorites') || []; const index = favorites.findIndex(item => item.id === detail.id); if (index > -1) { favorites.splice(index, 1); wx.showToast({ title: "已取消收藏", icon: "none" }); } else { favorites.push(detail); wx.showToast({ title: "收藏成功", icon: "success" }); } wx.setStorageSync('favorites', favorites); this.setData({ isFavorite: index === -1 }); }splice从数组删除或替换元素,findIndex找不到返回-1,恰好可以用index > -1判断是否存在。存储时直接存整个detail对象,收藏页渲染时不需要再按 id 查找数据源。
这里要特别注意:wx.setStorageSync是同步接口,数据量大时可能阻塞渲染层。收藏列表的条数不会超过几百条,同步接口完全够用;如果未来改成收藏文章、包含大量图片路径,再考虑wx.setStorage异步版本。
4.3 菜谱步骤用 rich-text 渲染,注意图片节点的坑
菜谱详情页的步骤区,有纯文本、有序号,还可能包含步骤图。用rich-text组件可以直接渲染 HTML 字符串,比逐段wx:for更灵活,适合从后台富文本编辑器同步内容。
<rich-text nodes="{{detailHtml}}" />对应的 js 侧是把 steps 数组拼成 HTML:
const detailHtml = detail.steps.map((step, idx) => `<p><span style="font-weight:bold">步骤${idx + 1}:</span>${step}</p>` ).join('');rich-text组件有两条局限:一是不能绑定事件,图片无法做点击预览;二是img标签默认不支持自适应宽度,需要给图片加style="max-width:100%"。如果步骤图较多,建议改用wx:for渲染图片列表,配wx.previewImage实现点击大图,体验更接近主流菜谱 App。
nodes属性支持 HTML 字符串,也支持节点数组。使用前最好把内容做一次清洗,去掉<script>等危险标签。虽然rich-text不会执行 JavaScript,但外部内容仍然存在样式注入的风险,清洗逻辑写成工具函数放在utils层。
5. 让菜谱小程序更容易被搜到:骨架屏与分享配置
5.1 首屏骨架屏的快速接入
菜谱列表页的网络图片加载通常需要几百毫秒,如果展示空白区域,用户容易误以为页面卡死。常见的做法是用骨架屏占位,在真数据返回前先渲染灰色色块。
不需要引入额外组件库,直接在当前页面的 wxml 中加一段:
<view wx:if="{{loading}}" class="skeleton-wrap"> <view class="skeleton-card" wx:for="{{[1,2,3,4]}}" wx:key="*this"> <view class="skeleton-img"></view> <view class="skeleton-line"></view> </view> </view> <view wx:else class="recipe-list"> <!-- 正常列表 --> </view>skeleton-img和skeleton-line的样式用灰色背景加border-radius,核心是给skeleton-img设置一个轻微的透明度动画,模拟加载中的呼吸感。骨架屏在本地数据源下几乎看不到效果,但如果换成了真实接口,这段代码是首屏体验的关键一环。
5.2 分享按钮和 onShareAppMessage 让菜谱获得免费流量
微信小程序没有主动推送能力,菜谱内容想要传播,主要靠用户分享。页面默认不显示分享入口,必须在 js 中定义onShareAppMessage。
onShareAppMessage() { const detail = this.data.detail; return { title: `【${detail.name}】的做法,一看就会`, path: `/pages/detail/detail?id=${detail.id}`, imageUrl: detail.cover }; }title是分享卡片标题,要带菜名;path必须包含参数,否则好友打开进入首页而不是具体菜品;imageUrl默认截取当前页面截图,菜谱场景主动传封面图,转化率更高。另外可以配合wx.showShareMenu开启右上角菜单里的分享按钮,让用户不点页面内按钮也能转发。
5.3 sitemap 配置决定小程序内容能否被搜索收录
微信小程序支持被搜索收录,前提是正确配置sitemap.json。菜谱类内容是非常典型的搜索需求,不配置或者配置成全部拒绝,相当于主动放弃搜索流量。
{ "rules": [ { "action": "allow", "page": "pages/detail/detail", "params": ["id"], "matching": "exact" }, { "action": "allow", "page": "pages/index/index" } ] }action决定允许还是禁止索引,page指定页面路径,params声明允许被索引的 url 参数名,matching是匹配模式,exact表示完全匹配。详情页是用户搜索菜名后的落地页,必须加入收录范围;收藏页和个人页属于隐私页面,不应当被索引。
最后一步是验证配置是否生效:在开发者工具中点击「编译」旁边的「普通编译」下拉菜单,选择「按 sitemap 编译」,工具会提示sitemap.json的匹配结果。上线后可以在小程序后台「统计-搜索」中看到关键词曝光和点击数据,菜谱类目的搜索词通常是菜名加做法,这块数据对后续内容选题有直接参考价值。
本文还有配套的精品资源,点击获取