ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

菜谱微信小程序开发实战:导航栏、支付与视频适配全解析

菜谱微信小程序开发实战:导航栏、支付与视频适配全解析 简介这是一份面向微信小程序初学者的菜谱大全项目源码以美食菜谱为业务场景完整演示了从页面搭建到交互逻辑的小程序开发流程。资源共26个文件压缩包仅19KB主要包含6个js逻辑文件、5个wxss样式文件、4个wxml页面结构文件、3个png图片资源以及json、xml等配置信息覆盖菜单、搜索、详情等页面模块整体目录结构清晰从app.json全局配置到列表、搜索、详情等子页面分模块摆放并附有README与修改日记便于对照学习与二次开发。目前已有2106人学习下载适合希望借助实际项目快速上手小程序开发的读者通过阅读这份资源可以掌握路由管理、数据请求、本地缓存、列表展示与页面交互等核心知识点是一份轻量且实用的入门级参考。1. 项目定位与整体设计为什么菜谱类小程序值得做1.1 菜谱小程序的需求画像与核心功能做微信小程序开发这几年我接过的项目里最常被问到的就是“想做个菜谱大全类的应用难不难”。说实话内容型小程序里菜谱、资讯、知识库这几种是典型到不能再典型的形态需求足够垂直、调用微信生态能力足够多用来练手或者做独立项目都非常合适。菜谱小程序的核心用户场景很清晰用户在做饭时打开小程序快速查询“今天吃什么”搜索某道菜的做法查看食材用量和步骤可能还要收藏菜谱、记录自己的做法甚至生成购物清单。这些都是高频率、短时长的操作恰好匹配小程序“即用即走”的产品属性。和纯H5网页版比小程序能享受微信的账号体系、模板消息、微信支付、分享卡片等原生能力和原生App比又省去了下载安装流程很适合菜谱这种“想起来了才看一眼”的工具型应用。从功能拆解来看一个完整的菜谱小程序应该包含这几个模块分类导航家常菜、川菜、烘焙等、关键词搜索、菜谱详情页食材、步骤、视频、收藏与历史记录、个人中心。如果再往商业化方向走还可能加上会员付费、积分签到、专栏课程、直播预告等功能。本文就围绕我实际开发菜谱类小程序过程中遇到的高频问题展开里面大部分坑都是微信小程序开发者会踩到的属于一眼看过去就能少走弯路的经验。1.2 技术选型原生小程序还是 uniapp做菜谱小程序之前首先要决定用原生微信小程序还是跨端框架。这个选择直接决定了后面踩坑的方式。我把两种方案的差异整理成了表格方便你对照自己的情况对比维度原生微信小程序uniapp上手成本需要学习WXML/WXSS入门快会Vue就能写跨端能力强性能体验最好渲染控制最细多一层编译复杂页面有损耗微信API覆盖度最新API都能第一时间使用部分能力需要封装或等社区更新调试体验微信开发者工具原生支持依赖HBuilderX联动偶尔抽风多端发布仅微信可打包App、H5、各端小程序我自己的习惯是如果是纯微信端且重视体验细节选原生如果后续要考虑App端选 uni-app。本文里讲到的导航栏高度、软键盘遮挡、视频全屏错位这类问题在原生和 uniapp 里都会遇到处理思路是一致的。后面除非特别说明“uniapp中”大部分内容两种技术栈通用。2. 从页面搭建到核心功能实现2.1 自定义导航栏顶部高度与胶囊对齐菜谱类小程序对页面要求干净清爽默认导航栏的背景色和字体颜色控制范围有限很多团队会选择自定义导航栏。但自定义导航栏的第一道关卡就是“顶部安全距离”的适配这也是“微信小程序自定义标题上边距怎么弄”这类问题被反复搜索的原因。微信小程序的自定义导航栏核心是两个数据状态栏高度statusBarHeight和胶囊按钮的位置。状态栏高度就是手机顶部显示电量、信号的那一条通过wx.getWindowInfo()或者wx.getSystemInfoSync()获取。胶囊按钮的位置需要用wx.getMenuButtonBoundingClientRect()获取这个方法返回胶囊按钮的上下左右坐标和宽高。导航栏的真实高度该怎么算我直接给出一个稳定可靠的公式const windowInfo wx.getWindowInfo(); const menuButton wx.getMenuButtonBoundingClientRect(); const statusBarHeight windowInfo.statusBarHeight; // 状态栏高度 const navBarHeight (menuButton.top - statusBarHeight) * 2 menuButton.height; // 导航栏高度 const totalHeight statusBarHeight navBarHeight; // 导航栏总高度为什么是(menuButton.top - statusBarHeight) * 2 menuButton.height因为胶囊按钮在导航栏垂直方向上是居中的胶囊上边到状态栏底部的距离加上胶囊下边到导航栏底部的距离两者是对称的。所以先用胶囊顶部位置减去状态栏高度得到“上方留白”乘以2后再加上胶囊本身高度就得到了导航栏的总高度。这里有个很重要的细节menuButton.top - statusBarHeight这个值在安卓和iOS上并不相同部分安卓机型的差异甚至能达到几像素到十几像素所以不要在代码里写死必须每次动态计算。还有iPhone 灵动岛机型的状态栏高度大约在59px左右比传统机型高如果不适配导航栏内容会顶到挖孔区域。正确获取之后自定义标题栏的容器高度直接设为totalHeight内部内容垂直居中即可。我在实际项目中还发现部分安卓低端机上wx.getMenuButtonBoundingClientRect()偶尔会返回空对象尤其是页面刚启动时调用。稳妥做法是加一个 fallback如果拿不到胶囊按钮位置就按黄金比例分配navBarHeight statusBarHeight * 1.6虽然不完全精确但至少不会导致导航栏彻底错位。2.2 搜索页与软键盘遮挡问题菜谱小程序里搜索是核心入口用户要快速输入菜名但“uniapp 微信小程序 手机软键盘会遮挡住查询内容”这个问题在原生小程序里也频繁出现。原因在于软键盘弹出时会把输入框顶起来但如果页面里搜索结果的容器是固定高度或者页面没有正确滚动键盘就会直接盖住当前正在查看的内容。解决这个问题有几个层次。第一层给输入框设置cursor-spacing属性这个属性表示输入框光标与键盘之间的距离单位是px建议设置成cursor-spacing20让输入框和搜索结果列表底部与软键盘保持至少20px的间距。第二层给页面根节点设置adjust-position。在原生小程序里页面配置或输入框所在的input组件默认会在键盘弹出时自动上推页面但如果adjust-position{{false}}就需要自己监听键盘高度并做页面滚动。建议保持默认的true让系统自动处理基础场景。第三层是uniapp开发中比较头疼的情况使用自定义导航栏时页面上推的高度计算不对结果被键盘顶起来后导航栏跟着乱跑。我的处理方式是监听onKeyboardHeightChange事件拿到键盘高度后手动设置底部容器的 padding-bottom。// 小程序页面生命周期中监听 onKeyboardHeightChange(e) { const { height } e; this.setData({ // 将页面底部安全区域撑高把内容顶出键盘区域 keyboardHeight: height }); }!-- 在搜索结果容器上动态绑定padding-bottom -- view classsearch-list stylepadding-bottom: {{keyboardHeight}}px; !-- 搜索列表内容 -- /view还有一点容易被忽略在 iOS 上软键盘的“搜索”按钮触发条件是小程序 input 组件设置confirm-typesearch同时配合bindconfirm事件处理搜索逻辑。很多新手只监听bindinput导致用户按下键盘上的搜索键没反应体验差一大截。2.3 菜谱列表、详情与图片保存菜谱列表页的渲染优化是内容型小程序的重要环节。数据量一大一次性setData上万条数据页面铁定卡顿甚至白屏。我的做法是前端分页加载每页20条配合onReachBottom触底加载下一页。同时图片列表用懒加载属性lazy-load服务端返回的图片地址加裁剪参数缩略图宽度控制在 300px~400px。这些细节对真实小程序体验影响极其明显做好之后滚动流畅度完全是两个级别。给图片加效果这种事听起来很简单但“uniapp微信小程序保存图片:saveImageToPhotosAlbum:fail”这个报错我见过太多团队卡在这里。原因无非三种一是没有获取相册权限二是图片路径不是本地路径三是用户之前拒绝过权限之后再次调用直接失败。保存图片的标准流程应该是这样的调用wx.getSetting检查是否已获得scope.writePhotosAlbum权限如果没有调用wx.authorize请求授权如果用户拒绝过授权wx.authorize会直接进入 fail 回调此时必须用wx.openSetting引导用户去设置页手动开启图片如果是网络地址不能直接用来保存需要先用wx.downloadFile下载到本地临时路径再调用保存接口。function saveImageToAlbum(imageUrl) { wx.getSetting({ success(res) { if (res.authSetting[scope.writePhotosAlbum]) { // 已授权直接下载并保存 downloadAndSave(imageUrl); } else if (res.authSetting[scope.writePhotosAlbum] false) { // 之前拒绝过引导打开设置页 wx.openSetting({ success(settingRes) { if (settingRes.authSetting[scope.writePhotosAlbum]) { downloadAndSave(imageUrl); } } }); } else { // 首次请求授权 wx.authorize({ scope: scope.writePhotosAlbum, success() { downloadAndSave(imageUrl); }, fail() { wx.showToast({ title: 需要相册权限才能保存, icon: none }); } }); } } }); }另外saveImageToPhotosAlbum在 iOS 和安卓上的表现也有差异。安卓上部分机型如果保存的是 base64 临时文件路径可能直接失败iOS 对图片格式要求更严格网络图片下载失败时返回路径为空保存自然失败。所以每次下载完成后都要校验res.statusCode 200和res.tempFilePath存在不能想当然直接保存。3. 支付、网络与多媒体功能的实战细节3.1 微信支付 v3 对接与“无可用的平台证书”问题菜谱小程序如果要做会员或者付费专栏绕不开微信支付。这几年新商户基本都要求对接 APIv3而开发者在对接时最常遇到的报错就是“微信支付v3对接 无可用的平台证书请在商户平台-api安全申请使用微信支付公钥”。先说清楚 V3 支付的整体结构商户号、AppID、APIv3密钥、商户私钥、商户证书序列号、平台证书/微信支付公钥。相比 V2 用 API 密钥做 HMAC-SHA256 签名V3 使用 RSA-SHA256 签名安全性更高但也更繁琐。“无可用的平台证书”这个错误的根因是微信支付 V3 的接口响应内容使用平台证书的公钥加密商户需要用平台证书解密。如果你的服务器上根本没有存平台证书文件SDK 在需要解密时就找不到可用证书于是抛错。解决方式有两种。第一种是手动下载平台证书登录微信支付商户平台在“API安全”菜单里申请获取平台证书然后下载到服务器配置到 SDK 的证书路径中。第二种是使用官方 SDK 的自动更新功能比如 Java 的wechatpay-java和 PHP 的wechatpay-php都支持通过certificates下载器定期获取并更新平台证书。自动更新的好处是一劳永逸平台证书每 5 年更换一次手动维护容易忘记。需要注意2023年后微信支付逐步推进“微信支付公钥”替代“平台证书”的策略。如果你是新的商户在商户平台看到的可能不是“下载平台证书”而是“申请微信支付公钥”。对接时以商户平台实际显示的为准。如果你在网上搜到的教程还在让你去下载平台证书但你的商户平台界面并没有这个入口大概率是微信支付已经给你切换到了公钥模式这时候就不用再纠结“没证书”的问题只需要下载公钥并配置到SDK里。另外我还遇到过一个非常离谱的情况小程序本身没有违规但支付功能突然提示“由于小程序违规支付功能暂时无法使用”。这个问题通常是平台侧的处罚限制不会因为代码修复而自动恢复。处理路径只有一条登录微信公众平台查看站内信和违规记录确认具体违规原因按指引发起申诉。如果是误判申诉后一般1-3个工作日会恢复。如果是确实违规需要整改后提交申诉或等待处罚期结束。所以菜谱类小程序如果涉及用户生成的菜品评论、图片上传一定记得接入微信的security.msgSecCheck和security.imgSecCheck内容安全接口否则被用户投诉或者被系统检测出违规内容轻则删帖重则封支付权限甚至下架。3.2 全局网络异常提示的统一实现移动端网络波动是常态“当网络不可用或者网络不好的时候如何全局统一显示网络不可用”这个问题很多开发者处理得很零散每个页面单独判断代码重复量大还容易出现漏网之鱼。我的方案是在请求层和全局层双管齐下。请求层封装统一的request方法在回调里统一处理错误码和网络错误。当wx.request的 fail 回调被触发或者返回的 statusCode 不属于 2xx就通过一个全局状态管理器记录当前“网络异常”状态。所有页面只需要监听这一个状态不需要各自写wx.getNetworkType。全局层在App的onLaunch里注册wx.onNetworkStatusChange监听网络断开或者从WiFi切到移动网络时主动更新状态。然后在小程序入口页面上挂一个全局的通用的“网络不可用”提示组件监听全局状态异常时显示遮罩条或全屏提示。// app.js App({ onLaunch() { wx.onNetworkStatusChange((res) { // 通知所有页面 const pages getCurrentPages(); pages.forEach((page) { if (page.onNetworkStatusChange typeof page.onNetworkStatusChange function) { page.onNetworkStatusChange(res); } }); }); } });// 页面中使用 Page({ data: { networkNotAvailable: false }, onNetworkStatusChange(res) { this.setData({ networkNotAvailable: !res.isConnected }); } });这样做有个好处网络恢复时res.isConnected会变回true页面可以自动隐藏提示并重新拉数据不需要用户手动刷新。实际开发中我还加了防抖逻辑避免网络在3秒内反复切换导致提示闪烁。具体做法是记录上次状态变化时间两次变化间隔小于3秒就忽略当前变化。3.3 video 组件与 swiper 嵌套的坑菜谱详情页如果带视频教程视频播放是最容易出问题的地方。最常见的是“微信小程序 iOS中swiper组件嵌套video组件导致全屏错位解决方案”和“微信小程序 video不能播放”。先解释 iOS 上 swiper 嵌套 video 的错位问题video 组件本质上是原生组件就算开启了same-layer-rendering同层渲染在 iOS 上全屏切换时video 的层级和坐标计算依然容易和 swiper 的内部动画冲突导致全屏后画面偏移或者黑屏。我的解决方案是全屏时不依赖 swiper 的自动滑动而是在bindfullscreenchange事件里手动处理。onFullscreenChange(e) { const isFullscreen e.detail.fullScreen; if (isFullscreen) { // 全屏时暂停swiper自动轮播防止内部动画干扰 this.setData({ autoplaySwiper: false }); } else { this.setData({ autoplaySwiper: true }); } }同时给 swiper 里的 video 设置object-fitcontain并确保页面级配置里开启sameLayerRendering: true。如果你只在 swiper 的第一屏放视频后面都是图片建议不要用 swiper 包裹视频改成横向 scroll-view这样可彻底避开嵌套问题。至于“video不能播放”我整理过一份排查清单按出现频率排序合法域名没有配置视频源如果是网络地址域名必须在小程序后台“开发管理-服务器域名-业务域名”里配置并校验通过。开发工具里勾选“不校验合法域名”只能缓解本地调试真机上依然会被拦。视频格式不支持小程序 video 组件对 HLSm3u8和 MP4 支持最好部分安卓机型对 FLV、MKV 格式支持差建议服务端转码为 HLS 或 MP4。没有绑定src到合法路径视频源地址必须是https://开头的网络地址或本地临时路径file://在真机上基本不可用。autoplay 被限制小程序对视频自动播放有策略限制iOS 上静音自动播放可以带声音自动播放会被拦截建议不要依赖自动播放让用户点击后播放。4. 调试、抓包与发布流程4.1 使用 burp suite 抓取微信小程序请求开发和排查线上问题时抓包是调试网络请求的必备手段。很多做安全的工程师习惯用 burp suite我发现不少小程序开发者也开始用 burp 抓小程序数据包来分析接口字段。Burp Suite 抓取 PC 端微信小程序的思路是这样的把手机或PC上的微信流量通过 HTTP 代理转发到 burpburp 作为中间人捕获 HTTPS 请求。但微信小程序默认不信任用户的根证书所以我们手动安装 burp 的 CA 证书到系统后还需要在微信开发者工具中关闭 HTTPS 证书校验或者将证书导入到手机/PC的系统证书库。我常用的操作流程启动 burp在 Proxy Options 里设置监听地址为本机IP和端口如 127.0.0.1:8080在微信开发者工具中打开“设置-代理设置”选择手动代理并填入 burp 的地址和端口如果抓真机上的小程序手机和电脑连同一个WiFi手机WiFi设置里配置HTTP代理为电脑IPburp端口用浏览器访问http://burp下载 CA 证书在手机设置中安装证书并信任回到小程序开发工具勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。这些流程做完burp 里就可以看到小程序的请求流量包括接口 URL、请求参数、响应内容。有一点要特别提醒抓包只适用于排查自己的项目不要去抓别人的生产环境小程序一方面不道德另一方面可能涉及隐私风险。4.2 HBuilderX开发小程序的各种报错与真机调试如果你用 uniapp 开发HBuilderX 直接 “运行到微信开发者工具” 时最经典的问题就是 “hbuilder运行微信小程序提示不是开发者”。这个报错的原因基本只有一个微信开发者工具安全设置里的“服务端口”没有开启或者当前登录微信号不是该项目 AppID 的开发者。解决步骤非常固定打开微信开发者工具点击右上角“设置-安全设置”打开“服务端口”开关确认 HBuilderX 和微信开发者工具登录的微信是同一个账号在微信公众平台后台把当前微信号添加为项目开发者。也有一种情况是 HBuilderX 内置的微信开发者工具路径配置错误在 HBuilderX 的“运行-运行到小程序模拟器-运行设置”中手动指定微信开发者工具的安装路径尤其是 mac 上经常需要定位到/Applications/wechatwebdevtools.app/Contents/MacOS/cli。真机调试时还要注意如果页面请求的接口域名没配到小程序后台真机上直接请求失败。本地开发时建议使用微信开发者工具里“本地调试”自带的代理功能或把接口环境切换成测试域名并配好合法域名“不校验合法域名”只对开发工具有效真机无效。4.3 小程序发布上架与审核避坑清单菜谱小程序从开发到上线发布流程本身并不复杂在微信开发者工具点击“上传”填写版本号和备注然后在公众平台“版本管理”里提交审核审核通过后点击“发布”。真正容易出问题的是类目选择和审核拒绝。菜谱类小程序建议选择“餐饮-菜谱”或“美食-菜谱”类目如果你只是做个内容展示工具不需要特殊资质。但如果涉及用户上传菜品、UGC评论、付费会员就可能需要《增值电信业务经营许可证》ICP备案或对应的文化经营资质不同的主体类型要求不一样最好提前在公众平台的“服务类目”里查清楚再开发。审核被拒的高频原因我整理了这份检查项审核拒绝原因解决办法缺少用户隐私保护指引在公众平台设置“用户隐私保护指引”详细声明收集哪些信息、用途是什么登录功能未符合规范不能强制用户授权手机号必须允许用户以游客身份浏览内容诱导分享或诱导关注去掉“分享得积分”“关注解锁”等诱导式按钮内容存在风险接入内容安全接口过滤用户发布的评论和图片类目选择错误重新选择与实际功能最匹配的服务类目5. 常见问题排查速查表5.1 从热搜词里收集的高频问题清单开发这几年我养成了一个习惯每隔一段时间就去翻一遍微信小程序相关的热搜词看看大家最近都在踩什么坑。整理出来的这些问题大部分不是高深的技术难题而是细节上的坑。下面这份速查表送给你们拿去对照排查即可问题可能原因解决方案安卓手机蓝牙搜索不到设备定位权限未开启蓝牙扫描需要同时开启位置服务在app.json中声明requiredPrivateInfos调用蓝牙前检查定位权限保存图片到相册失败授权被拒、图片路径不合法参考本文 2.3 节先下载再保存被拒绝时用openSetting引导自定义导航栏返回箭头消失页面配置navigationStyle: custom时自绘返回按钮被遮挡在页面中添加自定义返回按钮并通过getMenuButtonBoundingClientRect计算位置video 全屏后错位swiper 与 video 原生组件层级冲突绑定fullscreenchange全屏时暂停 swiper 自动播放或改用 scroll-view单选框样式不生效原生 radio 默认样式不易覆盖使用label包裹自定义样式或用 van-radio 等第三方组件课程表小程序提醒不生效订阅消息需用户主动订阅且一次性引导用户多次订阅并记录下一次提醒时间在服务端使用定时任务下发身份证引导拍摄不准摄像头/相册权限未处理或相机预览比例不对检查授权状态使用camera组件展示身份证取景框并把拍摄结果传给 OCR 接口识别内嵌H5后工具栏左侧返回箭头消失H5页面内没有调用wx.miniProgram.navigateBack在H5中引入微信JS-SDK返回按钮绑定wx.miniProgram.navigateBack()5.2 头像昵称获取逻辑调整后的处理建议微信小程序最近几年调整了用户头像昵称的获取规则以前一句wx.getUserProfile就能拿到头像和昵称现在接口已经下线用户授权后会拿到“微信用户”的通用头像和“微信用户”的昵称占位。菜谱类小程序如果需要用户自定义昵称现在的主流做法是使用微信官方提供的“头像昵称填写能力”用户点击头像组件时可以调用wx.chooseMedia让用户选择本地图片作为头像昵称则通过input组件的typenickname让用户直接填写。这既能保证合规又不会让用户因为隐私顾虑放弃登录。这个改动对开发者影响很大如果你的项目还是按旧逻辑去获取真名和头像用户在真机上体验到的就是“微信用户”这个占位名看起来很怪。我建议菜谱小程序里将头像和昵称改为可编辑的个人资料模块用户自己选择是否补充完整信息不要强制。5.3 最后分享几个冷门但实用的开发技巧第一个小程序顶部导航栏渐变色。原生navigationBarBackgroundColor只支持纯色想要渐变只能自定义导航栏然后给导航栏容器加background-image: linear-gradient同时需要注意渐变区域要覆盖到状态栏。第二个小程序的分享卡片图片需要用onShareAppMessage里的imageUrl字段图片必须是https://且建议 5:4 比例菜谱类应用建议用成品菜的高清横图。还有就是分享出去后用户点击卡片进入页面时要带一个来源标记参数方便统计分享带来的流量。第三个开发时一定要开vconsole看一下真机日志很多问题在开发者工具里不复现但真机上必现日志是唯一定位方式。做菜谱小程序这件事技术难度不高真正的门槛在细节适配和合规处理上。上面这些坑我自己都踩过反复查文档、看社区、尝试各种方案才总结出来希望能帮你少走一些弯路。如果你正在开发类似的内容型小程序遇到这里没写到的问题不妨按“页面表现 → 接口数据 → 权限配置 → 平台限制”的顺序排查大部分问题都能在这个链路里找到答案。本文还有配套的精品资源点击获取
返回列表