ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于uni-app的垃圾分类识别小程序开发实战

基于uni-app的垃圾分类识别小程序开发实战 你如果正在找一份能真正跑起来的微信小程序实战项目又恰好对“垃圾分类”这种自带流量和社会价值的方向感兴趣这篇内容应该能帮你省下不少摸索时间。我前段时间用 uni-app 在 HBuilderX 里完整开发了一款垃圾智能分类小程序从页面设计、图像识别到后端接口联调再到真机调试踩坑整个过程踩了不少雷也总结出一套可以直接复用的方案。这篇文章会把项目从零到上线的完整链路拆开讲清楚包括功能设计思路、核心技术点的实现方式以及那些文档里不会写但实际开发一定会遇到的各种坑。不管你是刚入门小程序开发的新手还是想找一个完整项目练手的老手都有参考价值。1. 项目整体设计与需求拆解1.1 这款垃圾分类小程序到底解决什么问题先说清楚这个项目的核心目标。拿我自己举例家里每次扔垃圾前几乎都要对着垃圾桶犹豫几秒尤其是电池、过期药品、奶茶杯这种容易分错的。网上去搜又太慢而且各地分类标准还不完全一样。这个小程序要解决的痛点其实很明确让用户掏出手机就能快速知道手里的垃圾属于哪一类并且知道该怎么投。在此基础上再叠加一些延伸功能比如按名称搜索、拍照识别、附近回收点查询和环保知识科普让工具变成一个有粘性的小助手。从产品定位上来看它不是一个纯工具型应用而是“工具 内容 服务”的模式。这种设计的好处是工具功能负责拉新和解决即时需求内容模块负责留存和提升使用时长回收点查询这类服务功能则为后续商业化留了接口。如果你只是做一个查分类的词典工具用户用完就走数据表现会很惨淡。这个项目的模块划分我从一开始就定成了五块首页快速查询、拍照识别、分类详情、回收点地图、个人中心。每个模块都有明确的使用场景和用户价值。1.2 功能模块拆解与技术选型思路先看整体功能结构。首页是整个产品的核心入口放了搜索框、常用分类快捷入口和拍照识别按钮。搜索框背后是一个关键词词库支持垃圾名称的模糊匹配拍照识别调用的是第三方的图像识别接口上传图片后返回分类结果。分类详情页按国家标准的四大类展开可回收物、有害垃圾、厨余垃圾、其他垃圾每一类都有详细的物品清单和投放注意事项。回收点模块接入的是高德地图的位置服务。个人中心则承载了登录状态、查询历史、收藏和关于我们。接下来说技术选型这是决定你后续开发效率和维护成本的关键一步。原生微信小程序开发当然可以但这个项目我选了 uni-app 框架核心原因是它一套代码可以同时编译到微信小程序、H5 和 App后续如果想扩展多端就不用重写。HBuilderX 作为开发工具对 uni-app 的支持最完整新建项目、运行到微信开发者工具、打包上传都是一键操作省去了很多环境配置的麻烦。语法层面用的是 Vue 2 的语法风格如果你熟悉 Vue上手的成本几乎为零。补充一句如果你是一个纯新手我的建议是不要一上来就研究原生小程序的复杂配置直接走 uni-app 这条路开发体验会友好很多。HBuilderX 安装完成后在微信开发者工具里打开服务端口设置HBuilderX 里点运行到小程序模拟器就能自动拉起微信开发者工具并编译。这个链路打通之后后续所有调试都会顺畅很多。1.3 为什么优先选择微信小程序平台垃圾分类类小程序选择微信平台原因有几层。第一微信小程序的调用路径最短聊天界面下拉一下就能进入用户不需要下载安装用完即走这非常符合查询类工具的使用习惯。第二微信生态自带分享和社交链我做了一个“分类挑战”小游戏功能用户答完题可以分享给好友 PK 分数这种裂变在原生 App 里很难实现。第三微信小程序有完善的登录体系和云开发能力微信登录拿到用户身份配合 uniCloud 可以快速搞定后端不需要自己买服务器。不过也要提醒一下微信小程序的审核对类目要求比较严格。垃圾分类这些功能本身没有问题但如果涉及拍照识别要确保使用的是正规的图像识别服务不要涉及敏感图片处理这个在提审时会查。另外个人主体的账号有一些类目限制建议提前在微信公众平台确认你的主体资质能覆盖要发布的服务类目否则开发完了上不了线就尴尬了。2. 开发前的准备工作与项目初始化2.1 HBuilderX 与微信开发者工具双端配置初始化项目之前先把环境准备好。开发这个项目我用了两套工具HBuilderX 负责写代码和编译微信开发者工具负责预览调试、查看控制台报错以及后续上传审核。你需要先在微信公众平台注册一个小程序账号拿到 AppID。在 HBuilderX 新建 uni-app 项目时选择“默认模板”然后在 manifest.json 里把微信小程序配置的 AppID 填进去。这里有一个容易被忽略的细节微信开发者工具的安全设置里必须开启“服务端口”否则 HBuilderX 无法自动唤起编译。另外建议把微信开发者工具设置为默认浏览器打开方式不然每次运行都会弹一堆无关界面。项目跑起来之后你在 HBuilderX 里改完代码保存微信开发者工具会自动刷新不需要手动重新编译这个热更新机制实测下来非常稳定可以放心依赖。2.2 页面目录结构与公共样式设计一个清晰的项目目录结构能少走很多弯路。我用的是 uni-app 默认的结构pages 下面按模块建文件夹home、identify、category、map、mine每个文件夹里放对应页面。static 放静态图片components 放自定义组件utils 放封装好的请求函数和公共方法store 用 Vuex 管理全局状态。公共样式的设计思路也值得聊一下。我的主色调用了绿色系因为这个色系和环保主题是天然匹配的。在 uni.scss 里统一定义了主色变量 $primary-color 和辅助色变量后面写页面时可以直接引用。底部 TabBar 用的是自定义图标这里要提醒一下TabBar 的图标在真机上有严格的尺寸和文件格式要求建议直接用 PNG 格式尺寸 81px * 81px而且必须放在 static 目录下不能放在子目录里否则真机上会显示不出图标。2.3 修改刚进入的加载页面很多新手问“修改刚进入的加载页面”怎么改这里多说一句。小程序启动时默认会有一个加载等待页面这个页面在小程序后台的“基本设置”里的“启动场景”可以配置。如果你想在启动时展示品牌相关的 logo 画面可以把它设置成一张带 logo 的图片。另外一个办法是做分包加载把核心页面放到主包其他不常用的页面拆到分包启动时只加载主包感知上启动速度会快很多。我实际测试下来小程序启动速度和首屏渲染速度是审核时一个隐性指标加载太久用户流失率非常高。启动页做精简化处理配合 lazyCodeLoading 选项可以把首包压缩到 200KB 以内体感上几乎是无感启动。这个配置在 manifest.json 的 mp-weixin 节点里加一句 “lazyCodeLoading”: “requiredComponents”就能实现按需注入代码不需要一次性加载所有页面组件的 JS。3. 核心功能模块的实现细节3.1 垃圾分类数据模型与查询逻辑垃圾分类查询是这个项目的心脏数据是否准确直接决定产品能不能用。我整理了大约 800 多条常见垃圾数据每一条都包含四个字段名称、分类、说明、投放建议。数据放在后端的数据库中前端不直接内置完整词库这样后续更新数据不用重新发版。查询接口设计的是模糊匹配。用户在首页输入关键词后前端通过防抖函数延迟 300ms 发起请求接口用 LIKE 模糊查询返回匹配列表。如果返回结果为空会触发一个“未收录”的提示文案同时引导用户提交这条垃圾的信息到后台这样数据可以持续完善。搜索结果点击进去是分类详情页展示该物品的分类、理由和投放注意事项比如“奶茶杯需要冲洗后投放”这种细化信息。这个功能看着简单但有一个小坑大家容易忽略中文模糊匹配要考虑同义词和别称。比如“电池”有人会搜“1号电池”“5号电池”有人会直接搜“南孚电池”词库设计时我加了一个同义词映射表把品牌名和通用名做了关联。这样即使数据量不大也能覆盖大部分真实搜索场景。3.2 图像识别功能从拍照到返回分类结果拍照识别是体现“智能”的核心功能也是开发工作量最大的模块。整体流程是用户授权相机或相册权限选择图片后上传到后端后端调用图像识别接口识别结果回传前端展示。需要注意的是微信小程序端并不直接去调第三方识别 API而是先把图片上传到自己的后端由后端统一转发识别请求这样一个是方便签名鉴权另一个是后续如果要换识别服务商不需要改前端代码。我选择对接的是百度 AI 的图像识别接口垃圾分类这个类目它在通用物体识别的基础上有专项模型准确率实测在 80% 左右。调用过程需要注册百度智能云账号创建应用后获取 API Key 和 Secret Key用这两个 key 去换取 access_token然后带 token 调识别接口。token 有效期是 30 天我们后端做了缓存不需要每次请求都重新换取。前端上传图片用的是 uni.chooseImage拿到临时文件路径后通过 uni.uploadFile 上传到后端接口。后端收到图片后先做压缩处理因为原图可能超过 4MB 的接口限制压缩之后再转给识别服务。识别结果返回后前端做一个分类的弹窗展示同时自动跳转到详情页。整个交互链路的体验是拍照 → 等待约 1.5 秒 → 看到结果。用户感知非常顺滑。关于权限有一个细节要处理好小程序的相机权限授权是一次性的用户如果第一次点了拒绝后续要引导他去设置页打开。我在代码里用 uni.getSetting 循环检测授权状态如果被拒绝就显示一个自定义弹窗引导用户点击按钮跳转到 openSetting 页面。3.3 地图找回收点高德地图的接入与定位问题排查回收点查询功能的实现依靠高德地图的微信小程序 SDK。接入的步骤是先在高德开放平台注册企业开发者账号创建应用时选择“微信小程序”平台拿到 Key 以后在项目的 manifest.json 里配置。地图组件使用的是高德的 map 组件标注点是后端接口返回的回收点经纬度列表。这里有一个很容易踩的坑小程序的地图组件只认腾讯地图的数据高德地图的数据格式和坐标系跟微信原生组件存在差异。我用的是高德的地图组件“amap”插件不需要原生 map 组件这样可以避免坐标系不一致的问题。如果你用原生 map 组件传入高德返回的 GCJ-02 坐标系经纬度在大部分手机上没问题但在部分 iOS 设备上会有偏差这个还特别难排查。定位功能我遇到一个典型问题在开发者工具里地图定位是准确的但发布到真机上苹果手机的位置经常偏到几百米开外。排查了很久发现是没做定位权限的授权判断用户在拒绝后没有重新拉起授权弹窗定位一直用的是上一次的缓存位置。解决方式是先调用 uni.getLocation 检测如果权限是 denied 状态就弹窗引导用户打开设置。另外回收点列表返回的是相对距离排序需要用 haversine 公式在前端实时根据用户当前位置计算距离这个逻辑在工具里调试没问题真机上时区导致的时间错位问题也遇到过后面我会在问题排查部分详细说。3.4 登录体系与用户信息获取微信小程序登录实际上走的是 code 换 token 的标准流程。前端通过 uni.login 获取临时 code把 code 传给后端后端拿着 code 去微信接口换取 openid 和 session_key然后生成自定义的登录 token 返回给前端前端把 token 存在 storage 里后续所有请求都带上这个 token 识别用户身份。这里需要特别提醒不要在小程序端直接拿微信返回的数据当作显示昵称头像的最终来源用户修改过微信昵称后如果不做同步页面会一直显示旧的昵称和头像。我在开发中遇到过一个需求更新用户信息到服务端后前端需要重新渲染页面的用户昵称当时直接写成了下面这种错误的方式// 错误写法key 是一个表达式不能通过点语法直接赋值 this.setData({ userinfo.nickname: that.data.nickname });正确的姿势是先获取最新的用户信息然后修改本地的 data 数据源再通过 setData 把整个 userinfo 对象重新赋值或者用中括号语法设置动态 key// 正确写法先更新本地数据源再整体 setData this.userInfo res.data.userInfo; this.setData({ userinfo: this.userInfo });实际开发中还要注意的一个问题是获取用户手机号和解密用户信息的接口已经改版多次现在获取头像昵称推荐使用“头像昵称填写能力”这个也是微信后台审核时的一个重点项不能用过时的 wx.getUserInfo 接口去获取真实身份信息。4. 后端接口设计与数据联动4.1 为什么要自建后端而不是只用云开发关于后端方案我纠结了一段时间最终选择了自建 Node.js 后端 MySQL 数据库而不是直接用微信云开发。原因是这个项目的识别功能和地图服务需要对接外部 API云开发虽然部署简单但写云函数要和腾讯云的环境绑定后续如果要迁移或者对接企业级服务灵活性会比较差。自建后端好处是接口的逻辑可以完全自己掌控而且调外部 API 时的签名鉴权都放在服务端不需要暴露密钥。我给后端定义了这么几组接口用户登录接口、垃圾分类查询接口、图片识别上传接口、回收点列表接口、收藏和查询历史接口。全部用 RESTful 风格请求返回 JSON结构统一是 { code, message, data }前端封装一个 request 函数统一处理响应码和错误提示。因为小程序要求接口必须是 HTTPS我开发阶段用 Nginx 做反向代理同时设置了合法域名校验这一点在开发者工具里可以勾选“不校验合法域名”跳过但真机预览时必须把接口域名配置到小程序后台的 request 合法域名里。4.2 接口安全与用户数据的处理自建后端的一个关键问题是接口安全。小程序端代码是可以被反编译的所以不能在前端存放任何密钥。所有第三方调用的密钥都只放在后端比如百度 AI 的 API Key、地图服务的 Key都是后端通过环境变量读取的。前端只通过接口交互杜绝了密钥泄露的风险。另外登录 token 的有效期设置成了 7 天过期后自动用 refresh_token 刷新。为了保证数据安全查询历史、收藏这类用户数据必须先通过路由中间件校验 token 是否合法才能访问数据库。这里有一个体验上的细节token 过期后用户的请求会报 401不能只弹“登录已过期”就完事而是在用户下次点击会触发登录的按钮时静默重新调 uni.login 来换新的 token用户是无感知的而不是直接让他重新走一遍登录流程。4.3 数据统计与运营需求作为一个小程序应用数据统计是必须要有的。我接入了微信官方的数据分析能力同时也定义了一些自定义事件比如搜索关键词、识别结果、收藏数量。这些事件上报到后端后会定时跑脚本统计出热门搜索词、垃圾种类的占比。数据表格如下用来支撑产品后续的迭代方向数据类型存储路径主要用途用户基础数据MySQL users 表用户登录状态管理查询日志日志表 分析脚本挖掘用户垃圾分类的常见误区图片识别记录图片存储 识别日志优化识别服务商选择回收点流量数据高德接口 访问日志分析用户地理位置分布这些数据驱动了一个实际的产品优化有一次统计发现“口红”和“粉底液”的搜索量特别高但词库里没有收录后来单独补充了美妆个护类目的条目搜索转化率提升了接近 20%。5. 问题排查与实用功能扩展5.1 遇到的问题与排查思路整理做了这个项目之后印象最深的不是功能实现而是一连串的兼容性问题。我整理了一张速查表这些问题如果你也做小程序开发大概率会遇到场景现象解决思路iOS 真机加载图片卡顿图片懒加载在 iOS 上偶发白屏对图片组件设置懒加载属性和占位图iOS 优先加载首屏图片scroll-view 中嵌入日期组件uni-datetime-picker 在 scroll-view 内点击无响应日期弹出层用 fixed 定位不放在 scroll-view 内部苹果手机定位偏移地图上的回收点与实际位置偏差数百米检查权限授权状态清缓存使用高德插件自带定位webview 与小程序通信H5 页面无法触达小程序内的事件使用 uni.postMessage 配合小程序端 onMessage 事件接收并处理顶部导航栏高度不一致页面标题在小屏手机上遮挡状态栏用 wx.getSystemInfo 的 statusBarHeight 动态设置占位高度微信开发者工具正常但真机异常setData 传递了 undefined 导致组件渲染失败所有接收到的接口数据先做默认值防御处理这里专门说一下 iOS 的渲染机制问题。小程序在 iOS 上的运行环境是 JavaScriptCore和安卓上使用的 V8 引擎在性能上有明显差异。复杂页面的渲染在 iOS 上会感觉稍微卡顿尤其是列表页同时渲染大量图片时。我的做法是尽量减少一次性渲染的数据量用分页加载替代一次性加载。另外一个重要优化是列表页图片的懒加载给 image 组件加上 lazy-load 属性后整个页面滚动流畅度提升非常明显。5.2 Charles 抓包验证小程序接口数据在正式上线前我担心后端接口的数据返回有问题用 Charles 做了一次小程序的数据抓包验证。这个操作在联调阶段非常有用。步骤是电脑上打开 Charles 并开启 SSL 代理手机和电脑连同一个 Wi-Fi把手机的 HTTP 代理手动设置成电脑的 IP 和端口手机上访问 chls.pro/ssl 安装证书之后微信小程序里发出的所有 HTTPS 请求都能在 Charles 上看到。不过新版的小程序可能无法直接抓包原因是微信官方对小程序的网络安全做了升级需要配置忽略 SSL 校验才能正常抓包。这个操作相对专业一般开发阶段在 Charles 里设置好即可。抓包验证的主要目的是确认前端传给后端的参数和后端返回的数据是否符合预期如果后端接口返回报错但前端没有捕获到抓包一下就能定位是网络问题、接口逻辑问题还是数据格式问题。5.3 导出 Excel 和下载文件的实际场景很多小程序项目会涉及数据导出的需求我这个项目里也有一个管理后台功能需要把用户查询日志导出成 Excel 表格。微信公众号后端返回的 Stream 流可以直接让前端下载但小程序端不能直接保存 Excel 文件到本地相册。实际的解决方案是后端把 Excel 生成后放到临时存储返回一个下载 URL前端可以用 uni.downloadFile 下载后配合 wx.openDocument 打开预览。如果是 ZIP 包用法类似uni.downloadFile 下载后判断文件后缀并对文件做解压处理。这里有一个文件存储的路径问题在开发调试中如果要用到本地文件存储可以存储到wx.env.USER_DATA_PATH目录下这个目录在小程序被移除前是长期存在的。但要注意OTA 更新小程序版本时这个目录的存储内容可能会被系统清除重要的数据不能只存这个地方还是建议重要数据同步到后端数据库里。5.4 分享、长按拖拽与加载性能优化分享功能是所有小程序裂变的标配。我在详情页右上角的胶囊菜单里默认隐藏了“分享到朋友圈”的选项只保留了“转发给好友”的按钮因为个人主体的小程序在分享到朋友圈时有审核门槛设置不当会被平台限制。这里的“右上角三个点和圆圈怎么关闭”是很多人的疑问那个胶囊按钮是微信原生提供的无法直接关闭但你可以通过 wx.hideShareMenu 控制它是否包含分享相关操作。长按拖拽滚动的需求在回收点列表中遇到过比如用户要在列表里通过长按某个回收点拖拽到地图上做标记。这个需求在小程序里实现起来有点绕因为小程序的滚动容器 scroll-view 默认不支持拖拽排序。我是通过触摸事件 touchstart、touchmove、touchend 手动计算拖拽位移配合 CSS transform 实现视觉上的拖拽效果数据层面再通过 splice 重新排列。这个方案的性能极限大概在 50 条以内超过这个量级会明显卡顿建议数据量大时改用上下移按钮或者分页展示。性能优化方面我在首页开启了对分包的支持把不常用但体积较大的页面独立拆到 subpackage 中主包体积缩小了约 40%。配合前面提到的 lazyCodeLoading 配置首屏加载速度肉眼可见地变快。设置页面、用户协议、隐私协议这类低频访问页面全部放到分包后续新增功能也尽量走分包路径这是一个长期收益的规划。5.5 小程序的页面设计思路页面的第一印象会直接影响用户留存这个项目里我花了不少心思在设计上。首页顶部用的是渐变色的搜索栏中间部分是拍照识别的卡片式按钮下方是四大分类的 icon 入口。颜色搭配上用环保绿做主题色配上白色和浅灰色的底色视觉上足够清爽。TabBar 的图标我用了线性风格选图标的时候一定要记得准备选中和不选中两套样式否则状态切换时会没有区分感。页面设计上的一个实用技巧是给每个区块留足呼吸感不要所有元素都怼在一屏上。特别是首页用户进来的第一屏只需要看到搜索框、拍照按钮和四大分类尽量减少视觉干扰。详情页则把分类颜色作为背景主色调比如可回收物用蓝色、有害垃圾用红色、厨余垃圾用绿色、其他垃圾用灰色用户看图的一瞬间就能判断分类这个设计在测试中反馈很好。给新手的提示开发阶段心态要放平。小程序和传统网页不一样样式兼容和真机适配的问题特别多遇到报错先看报错堆栈其次查文档最后才去搜社区大部分问题都是小配置导致的不要一开始就想推翻重来。6. 真机调试与上线经验6.1 从开发者工具到真机预览的必踩流程开发者工具里一切正常一到真机就各种问题这是小程序开发最典型的场景。所以我强烈建议从项目第一天起就养成频繁真机预览的习惯不要等到功能做完了再统一测。微信开发者工具里点“预览”会生成一个二维码用手机微信扫码就能在真机上打开小程序。真机上的运行环境更接近真实用户一些开发者工具不会报的兼容性问题都会暴露出来。真机调试有几个细节值得注意第一真机预览时使用的接口域名必须在小程序后台配置合法域名否则所有请求都会报 blocked第二真机上调试时建议开启调试模式这样可以在真机上看到 vConsole 的日志输出排查错误方便很多第三真机的相机权限、定位权限要反复验证特别是授权被拒绝后的引导流程是否顺畅。我遇到过的最耗时的两个问题都发生在真机环境一个是苹果手机上滚动页面时视频和图片等媒体资源会有偶发性的加载异常另一个是不同机型对页面底部安全区的适配差异比较大。关于安全区的问题解决方法是给底部元素加 padding-bottom 动态适配 home 指示条的高度这个高度可以通过 wx.getWindowInfo 拿到 screenHeight 和 safeArea 的差值来计算。页面底部有固定按钮的应用一定要处理这个否则 iPhone X 之后的全屏机型上按钮会被手势条挡住。6.2 版本发布与审核注意事项小程序开发完成后发布上线前有一个审核流程。提审之前先要用真机测试一遍核心功能尤其是登录、支付如果有、定位权限这些和平台规范强相关的功能点。审核时会重点检查隐私政策、用户协议是否完备如果涉及用户信息收集但界面上没有展示隐私弹窗直接被拒的概率非常非常高。个人主体的小程序还需要注意类目问题比如地图导航、医疗健康、金融这类敏感类目个人主体大多无法开通所以策划功能时要提前评估类目是否符合主体资质。我把审核的经验总结成四个字提前自测。审核不过的地方页面顶部会有明确的违规原因把这些问题都收集起来开会修正后再提审。实际乐观估计从提审到通过需要 1 到 3 个工作日所以发布节点要预留好时间不要掐着活动上线的那一天才提审那样很容易翻车。提审时还有一个容易忽略的细节上传版本时要设置体验版并配置体验成员。在微信公众平台的“管理-版本管理”里上传成功后可以邀请体验成员扫描预览发现问题可以随时修改。这个“测试版”的用途很多人不清楚以为只有正式发布才能测试实际上体验版就是专门用来给开发者和测试人员做上架前验证的设置好之后测试也可以脱离开发者工具直接用微信扫码测试完整功能。6.3 发布后的运营与迭代计划上线不是终点运营数据反馈的迭代才让产品真正成长。小程序上线初期我重点看三个指标首屏加载耗时、次日留存率、搜索点击转化率。首屏加载耗时直接和小程序体积相关如果超过 3 秒用户流失率会明显提升次日留存率方面只有小游戏之类的休闲产品能维持较高留存工具型小程序首周留存能到 10% 就已经不错了搜索点击转化率则直接反映词库质量如果搜索某个词但结果为空用户会立刻离开。基于数据反馈我规划了两个迭代方向。一个是做基于位置的智能推荐根据用户所在小区附近的回收点开放情况推送对应的分类指南另一个是增加垃圾分类学习打卡功能用积分体系提升用户粘性。前者需要对接更多地理位置数据后者需要完善用户体系但这两个方向都是基于真实用户需求提出的不是凭空想象出来的功能。收藏这个小技巧发布后一定要在微信公众平台开启「小程序码」把它放在文章、海报和菜单栏用户扫码和搜索进入的比例大概是 6 : 4二维码入口对增加新用户的效果非常明显。7. 常用功能模块的代码级实现7.1 请求封装与登录态管理小程序的接口请求需要一个统一管理的地方我在 utils 目录下写了一个 request.js对 uni.request 做了二次封装。封装的核心功能包括自动携带 token、统一处理 HTTP 状态码、超时重试、错误提示弹窗以及在收到 401 时自动触发重新登录的逻辑。实际开发中不少初学者在每个页面里直接写 uni.request一旦接口地址变更或者需要统一传公共参数改起来就非常痛苦。登录态的代码层面可以这样设计// utils/auth.js const TOKEN_KEY access_token; export function getToken() { return uni.getStorageSync(TOKEN_KEY) || ; } export function setToken(token) { uni.setStorageSync(TOKEN_KEY, token); } export function clearToken() { uni.removeStorageSync(TOKEN_KEY); }每次请求发出前拦截检查 token 是否存在如果不存在就先用 uni.login 拿 code发请求换 token之后再用真实的业务请求。这个逻辑会有一个并发问题如果首屏多个请求同时出发会同时调多次 uni.login。解决方式是维护一个全局的 promise第一次触发登录后把 promise 存起来后面的请求都等待这个 promise 完成。这个“登录防重入”的写法是我在开发中被并发请求坑过一次之后才加上的写出来给后来者提个醒。// request.js 中的关键逻辑片段 let loginPromise null; function ensureLogin() { if (!getToken()) { if (!loginPromise) { loginPromise new Promise((resolve, reject) { uni.login({ success: (res) { // 用 res.code 换取业务 token exchangeCodeForToken(res.code).then(token { setToken(token); resolve(token); }).catch(reject); } }); }).finally(() { loginPromise null; }); } return loginPromise; } return Promise.resolve(getToken()); }7.2 页面数据绑定与渲染优化微信小程序和 Vue 的差异之一在于小程序里修改数据必须使用 setData而在 Vue 中直接操作 data 就可以了。uni-app 在 H5 端和 App 端让你感觉像在写 Vue但编译到微信小程序时本质上还是编译成了小程序的 setData 调用。这意味着一个很大的性能陷阱在列表渲染时如果频繁 setData 整个列表页面会非常卡。我的优化经验是三个层面。第一是精细更新不要整页 setData只更新变化的那部分数据。比如点击收藏后只需要更新对应那条数据的收藏状态不需要把整个列表重新 setData 一遍。第二是使用节流对滚动刷新、搜索输入这类高频操作做节流减少 setData 频率。第三是合理拆分组件把页面拆成多个子组件每个组件的 setData 只影响自己作用域的渲染互不干扰。这个对原生小程序同样有效但对 uni-app 尤其重要因为 uni-app 转译到小程序后组件间通信的性能损耗比原生要大。动态修改某个列表项的数据是一个经常出现的需求很多人会写这种代码// 不优雅但不报错的写法 this.setData({ [list[ index ].isCollect]: true });小程序支持这种路径字符串赋值因为小程序的 setData 支持“键路径”格式的 dataPath。实际上这个语法在小程序端是可以直接使用的也不需要先深拷贝。但如果数据层级嵌套过深比如list[3].children[0].title这种建议还是把这一项拎出来单独处理数据可读性会好很多。7.3 页面间通信与参数传递小程序页面之间跳转传参有两种常用方式一种是 URL 带参数另一种是全局状态。URL 传参适合小数据量的业务逻辑比如从列表页跳详情页时传一个 id 过去。全局状态适合跨页面共享的数据比如用户登录状态、分类选项的选中状态。URL 传参有一个非常隐蔽的坑如果参数值包含特殊字符比如 、?、#直接拼接在 URL 后面会导致 base64 编码出问题。解决方案是用 encodeURIComponent 处理参数。我调试一个分类详情跳转时就因为物品名称里带了个“”符号整整排查了一个下午。这是大家在开发中很容易忽略但必须一开始就避开的坑。各页面间的事件通信我用的是 uni.$emit 和 uni.$on 的全局事件方案。这个在 uni-app 里跨页面传数据非常方便但有一个问题要记住页面卸载时要手动 uni.$off 移除监听否则组件销毁后回调还会被触发导致数据异常。我写了一个统一的页面销毁钩子把所有全局事件监听都清理干净这个隐性 bug 避免了很多次。7.4 自定义导航和顶部导航栏适配微信小程序默认的导航栏是白色的标题文字也是黑色的如果你想让页面顶部颜色和页面风格统一就要自定义导航栏。设置方式是在页面的 json 配置中设置navigationStyle: custom然后自己写一个 nav-bar 组件放在页面顶部。自定义导航栏后状态栏的高度需要自己处理否则内容会顶到手机听筒的位置。以下是获取状态栏高度并动态设置占位的常见写法// 在 onLoad 阶段获取状态栏和导航栏高度 const systemInfo uni.getSystemInfoSync(); this.statusBarHeight systemInfo.statusBarHeight; const menuButtonInfo uni.getMenuButtonBoundingClientRect(); this.navBarHeight (menuButtonInfo.top - this.statusBarHeight) * 2 menuButtonInfo.height这个公式计算出来的导航栏高度在绝大多数真机上都是准的因为 menuButtonInfo 提供的是右上角胶囊按钮的位置信息用它反推导航栏高度是最可靠的方案。调试的时候可以先在开发者工具里加上模拟手机型号的设备从 iPhone 6 到 iPhone 15 都切一遍基本能覆盖 90% 以上的机型适配问题。7.5 下载附件和打开文档的实现方式在管理后台场景里用户可能需要下载容器附带的说明书文件这个文件可能是 PDF、Excel 或者压缩包。小程序要打开这些文件不能直接用a标签跳转而是要走 uni.downloadFile 配合 wx.openDocument 的流程uni.downloadFile({ url: https://example.com/files/guide.pdf, success: (res) { if (res.statusCode 200) { wx.openDocument({ filePath: res.tempFilePath, fileType: pdf, showMenu: true, success: () console.log(打开文档成功) }); } } });将文件先下载到本地临时目录再打开这是小程序的规范。另外在调用 wx.openDocument 时加上 showMenu 参数用户右上角菜单才能出现“转发”“收藏”等选项。如果你要在本地写文件临时路径放在wx.env.USER_DATA_PATH下但注意它是临时的App 更新或缓存清理后可能丢失重要数据务必同步到后端。这一套文件交互的流程和 H5 完全不同刚接触小程序开发的朋友容易在这个地方产生困惑。8. 一些想额外分享的心得借着这次开发垃圾分类小程序的过程再把几个我踩坑之后感受最深的小点拿出来单独说说。第一点关于第三方组件的使用。小程序生态里有大量现成的组件库比如 uView、ColorUI 等功能确实很全但引入前一定要评估体积。很多组件库动辄几百 KB引进来之后主包体积直线上升。我的处理方式是只挑需要的组件按需引入而不是整个 UI 库全量安装。uView 里的某些表单和弹窗组件比较实用但绝大多数 UI 组件我都自己用原生样式写了最终的包体积控制在 300KB 以内加载速度就是生命的快一分是一分。第二点关于测试的覆盖范围。小程序开发和前端开发不太一样真机兼容、不同操作系统版本、不同屏幕尺寸都会导致差异。我在上线前花时间租了一台测试云服务跑了一批市面上主流机型的自动化测试虽然成本不算低但确实发现问题很多包括一部 Android 老机型上拍照后图片方向不对的问题。越早发现兼容性问题修复成本越低这个道理在所有软件开发里都一样。第三点关于项目规划。把一个想法落地成交互流畅的小程序最核心的其实是“范围控制”。我一开始想做的事情特别多社区、排行榜、商城、nav, 后面果断砍掉了大部分才在三个月内把核心体验打磨出来。小团队和独立开发者一定要学会做减法把垃圾分类查询、拍照识别、回收点地图这三个核心功能做好就已经能形成一个完整可用的产品了。垃圾分类这个方向的环境价值和社会价值都是实打实的小程序的轻量特点又特别适合这种“即用即走”的民生工具。如果你正在规划自己的小程序项目可以把它当作一个需求完整、边界清晰、实现路径成熟的练手选题。开发过程中学到的东西远不止一套技术栈而是从需求分析到产品设计再到工程落地的完整方法论。
返回列表