
做微信小程序开发这几年我最常被问的一句话就是“一个人到底能不能完整做出一款小程序”我的回答一直是能前提是你愿意把需求砍到足够小把计划拆到足够细。这篇开发日记记录的就是我最近一个人从零开始做“博物系统”小程序的完整过程。所谓博物系统说白了就是一个面向自然爱好者的小型知识库加场馆导览工具用户可以在上面浏览动物、植物、矿物、古生物等分类下的科普卡片也能搜索想了解的内容后续还打算接入地图让大家直接找到附近的自然博物馆和科普场馆。整个系列我打算分成几篇来写第一篇先把最基础也最容易被忽略的东西讲清楚为什么选微信小程序、怎么搭起项目骨架、数据从哪来、列表页怎么做、踩了哪些坑。我不会只丢结论每一个关键选择背后的原因、每一处让我抓狂的报错都会尽量还原现场。如果你正打算入坑微信小程序开发或者想做一个内容展示类的小程序却不知道怎么下手这篇内容应该能帮你少走不少弯路。1. 项目从0开始的思考我为什么偏偏选微信小程序1.1 博物系统到底要做什么在动手写代码之前我最先做的事情不是打开开发者工具而是坐下来把“博物系统”这四个字拆开想清楚它到底要解决什么问题。市面上的自然科普App其实不少但大部分都做得太重动不动就要注册账号、签到积分、社区互动对只想查一下“这只鸟叫什么”的用户来说学习成本太高了。所以我给自己定的产品方向非常克制一个轻量级的博物知识浏览工具。核心场景就是用户打开小程序看到分类清晰的科普卡片点进去能读到简洁准确的介绍需要时能搜索、能收藏后续可以查看附近的科普场馆。第一版不需要用户系统不需要评论不需要支付就专心把“浏览”和“查询”这两件事做好。想清楚这一点之后技术选型就变得异常轻松。后端暂时不需要自建服务器内容用静态JSON加图片资源就能撑起第一版地图能力微信小程序本身就提供了组件支持收藏功能用本地缓存就能实现。这套方案一个人开发两到三周就能上线一个能看能用的版本完全符合“先跑起来再迭代”的思路。1.2 为什么不用H5、原生App或者UniApp很多朋友做类似项目时会纠结技术选型我直接说结论对于“博物系统”这种内容展示型、强依赖微信生态传播的项目微信小程序是当前最省力的方案。H5虽然开发快但入口深、没有原生的分享卡片和订阅消息能力用户留存基本靠缘分App开发和上架成本高审核周期长对个人开发者非常不友好Flutter、React Native这类跨端框架虽然性能好但学习和调试成本高第一版根本没必要。UniApp我也认真考虑过它能一套代码多端发布听起来很香。但实际接触下来我发现它在微信小程序端的兼容性偶尔需要额外适配而且多端需求在这个项目里根本不存在与其背着跨端的包袱不如直接回归微信开发者工具加原生小程序语法少一层封装就少一类问题。1.3 开发环境与工具链准备清单这一节分享我的实际工具组合不是什么高深配置但对新手来说照着配能省很多事。首先去微信公众平台注册一个小程序账号个人主体就可以注册完在“开发管理”里拿到AppID。注意不要用测试号长期开发因为测试号不支持很多真实接口权限等你后期想加订阅消息、地图功能时会卡住。开发工具方面我主力用的是微信开发者工具稳定版写代码用的是VS Code后者主要因为插件生态好、界面舒服。两个工具配合的方式是代码在VS Code里写保存后切到微信开发者工具看效果。有人问为什么不直接在微信开发者工具里写因为它自带的编辑器只能说够用和VS Code的代码补全、Git集成体验差距明显。另外我还开了微信开发者工具的“热重载”功能改完代码不用手动刷新页面会自动更新这个开关在“设置-通用设置”里默认是开启的很方便。2. 搭地基从注册小程序到跑通第一个页面2.1 注册、AppID与开发者权限配置注册流程没什么好说的按官网提示一步步填就行我提醒几个容易忽略的细节。第一邮箱不要用QQ邮箱亲测在个别环节收验证码偶发延迟用常见的163或Gmail都行。第二个人主体小程序虽然不能开通微信支付但信息展示、地图、订阅消息这些核心功能都不受影响内容类项目完全够用。第三注册完成后一定要在“成员管理”里把自己添加为项目开发者否则后面用开发者工具扫码登录时会提示没有权限。拿到AppID后还有一步容易被忽略打开“开发设置”把服务器域名配置好。如果你的项目第一版完全用本地静态数据加云开发这一步可以先不着急但只要你后续打算请求自己的HTTPS接口就必须提前把域名加进白名单。这里有个经验域名一定要用HTTPS而且备案要提前做因为备案审核周期通常要一两周等到上线前才申请大概率会耽误事。2.2 创建项目传参和目录结构的一次性规划打开微信开发者工具选择“小程序项目”填入AppID项目名称填“博物系统”模板选择“不使用模板”这样会生成一个最干净的空项目。很多人喜欢选带模板的初始化项目但我建议第一版还是从空白开始因为模板里会带一堆示例页面和冗余代码删起来费劲还可能残留不稳定的依赖。目录结构我一开始就规划好后续没有大改过。pages下面按功能分目录比如pages/index是首页pages/category是分类页pages/search是搜索页pages/detail是详情页。utils目录放公共方法比如防抖函数、数据请求方法。images放本地图标data放静态JSON数据。assets放公共样式和全局图片。这个结构看起来很常规但好处是随着页面增多不会乱每新增一个功能模块我知道该去哪里找对应代码。有一个小坑要提一下项目创建时注意基础库版本的选择。微信开发者工具默认会用最新基础库但真机用户的微信版本未必都更新到最新所以我会在app.json里显式声明一个向下兼容的版本号。具体操作是在app.json中加一行“libVersion”配置一般选当前最新版本往前推两三个版本就够用。设置太低的话一些新API用不了设置太高老手机用户打开会白屏。2.3 配置底部导航栏与顶部导航栏适配博物系统的信息架构我设计成三个主频道首页、分类、我的。三个页面对应三个底部Tab这个通过app.json里的tabBar字段就能配置。tabBar的图标需要准备两种状态普通状态和选中状态图片尺寸官方建议81px乘81px格式用PNG。我没有设计能力就用在线图标库下载了三个简单图标稍微改了下颜色。顶部导航栏这一块是很多新手容易翻车的地方尤其是iPhone的刘海屏和不同Android机型的异形屏。微信小程序默认的navigationBar是系统提供的高度在不同机型上不一样如果页面内容需要根据导航栏高度做适配直接写死像素值肯定不行。我的做法是用wx.getMenuButtonBoundingClientRect()拿到右上角胶囊按钮的位置信息再结合系统信息计算导航栏的真实高度和状态栏高度。这个方法我封装成了一个工具函数放在utils里所有页面需要时直接调用实测在主流机型上都很稳。3. 博物系统的数据地基从JSON到静态资源管理3.1 分类体系设计像整理书房一样整理知识博物系统的核心资产是内容而内容要是没有清晰的分类体系后面做什么都别扭。我参考自然博物馆的常见布展逻辑把第一版内容分成五个大类哺乳动物、鸟类、植物、矿物、古生物。每个大类下面再设若干小类比如鸟类下面分鸣禽、猛禽、水鸟、攀禽植物下面分乔木、灌木、草本、蕨类。这个分类体系不追求学术严谨但求用户一眼能看懂、能快速定位。每个具体词条我设计了统一的字段结构包含名称、学名或拉丁名、分类层级、简介、特征描述、分布区域、保护等级、图片地址、详情页路径等。字段统一的好处是列表页和详情页可以共用一套渲染逻辑新增词条时只需要按模板填数据不需要改页面代码。我把所有词条数据放在data/species.js里用数组嵌套对象的方式组织首页展示推荐词条时只要按条件过滤就好。3.2 图片资源策略本地还是远程博物系统是图片密集型应用图片资源的组织方式直接影响加载速度和开发效率。我第一版把所有图片都放在项目的assets/images目录下图片名称用“分类_词条编号”的规则命名比如bird_001.jpg。这样做的优点是开发和真机调试时不用考虑网络请求加载迅速缺点也很明显小程序主包大小限制是2MB图片稍微多一点就超了所以正式上线前必须把图片迁到远程。迁移远程我选了比较稳妥的方案图片传到对象存储比如腾讯云COS或阿里云OSS开启CDN加速然后把URL存进JSON数据里。静态JSON数据文件本身很小放在小程序包里没压力图片资源全部走网络请求这样既能控制包体积又能利用CDN提升加载速度。这里提醒一下远程图片的域名也要配置到后台的downloadFile合法域名里否则真机上图片会加载不出来。3.3 用WXML和WXSS快速渲染科普卡片列表数据准备好之后渲染列表是件很愉快的事。首页的推荐词条我用了一个横向滑动的卡片列表用户轻轻一滑就能看到不同分类的精彩内容。卡片的设计上我坚持“图大、字少、信息层级清楚”上部分是图片占了卡片大概三分之二的高度下面依次是名称、分类标签和一行的简介。WXML里用wx:for循环渲染数组每一项绑定点击事件跳转到详情页。样式部分我用的是WXSS整体风格走清爽路线背景色用浅灰偏白卡片用白色圆角加轻微阴影。文字大小上标题用32rpx正文用28rpx标签用24rpx。rpx这个微信小程序特有的单位是自适应宽度的设计稿按750rpx宽度来不同屏幕下会自动缩放不用像H5那样写一堆媒体查询。只提一个注意点rpx在小屏Android机上个别时候会四舍五入出现细线缝隙卡片之间留一点间距就能规避。4. 核心交互实现搜索、筛选与详情跳转4.1 搜索功能防抖和关键词匹配的取舍博物系统的搜索功能我的实现思路是搜索框输入关键词实时从词条数组里匹配名称和描述把结果用列表展示出来。这里有个性能问题必须处理用户输入每个字都会触发一次匹配如果词条库变大一次性渲染几百个结果会让页面卡顿。我的解法是加一个300毫秒的防抖函数用户停止输入300毫秒后才真正执行搜索把频繁触发的计算合并成一次。防抖函数写起来很简单就是setTimeout加clearTimeout的组合我放在utils/debounce.js里。匹配逻辑上一开始想做拼音首字母匹配但考虑到第一版词条数量有限就只做了中文关键词的模糊匹配也就是用indexOf判断关键词是否出现在名称或简介中。这里有个总结不要为了“显得高级”一开始就堆功能模糊匹配在数据量小的时候体验完全不差等以后数据量上来了再优化也不迟。4.2 分类筛选多选标签与单选互斥的设计细节分类页的核心交互是筛选。页面上方是一排分类标签下方是词条列表。我采用了一种混合的筛选方式顶部五个大分类标签是单选互斥的点击“鸟类”就只看鸟类但鸟类内部的小类标签支持多选比如用户可以同时勾选“鸣禽”和“攀禽”。实现的时候大分类用radio-group实现小分类用checkbox-group实现选中小类后用filter方法过滤数据同时更新页面显示的数量。这个设计有个细节值得说当用户切换大分类时小类的选中状态一定要重置否则会出现“选了鸟类的水鸟又切到哺乳动物筛选结果却是空的”这种反直觉情况。做法是在大分类的change事件里把存放小类选中状态的数组清空。这种交互逻辑虽然代码改动只有几行但直接影响用户对产品专业程度的感知值得认真对待。4.3 详情页跳转参数传递和常见报错排查词条卡片点击之后要跳转到详情页我用的是wx.navigateTo加上url参数传递的方式比如url: /pages/detail/detail?idbird_001。详情页在onLoad生命周期里通过options.id拿到参数再用这个id从数据源中找到对应的词条对象渲染到页面上。这是小程序最基础也最常用的页面通信方式简单直接适合内容展示型页面。这里分享一个排查经验。我遇到过一个问题页面跳转一直报类似“component pages/detail/detail does not have a method navigateBack”的错误一开始我以为是自己方法名写错了后来才发现是app.json的pages数组里根本没有注册这个页面文件或者是路径写错了。小程序里所有页面都必须先在app.json里声明没有声明的页面即使文件存在也无法跳转。另一个容易踩的坑是跳转URL里的参数值如果包含特殊字符比如中文或空格需要先用encodeURIComponent编码再在接收端用decodeURIComponent解码。5. 进阶能力补齐地图定位、订阅消息与云开发5.1 附近场馆地图用map组件标出周边科普点博物系统第一版上线后我很快就发现用户有个隐藏需求看到了某种动物想去附近的自然博物馆或科普场馆实地看看。于是第二版规划了“附近场馆”功能。实现方式并不复杂页面里放一个map组件通过wx.getLocation拿到用户当前位置再用wx.chooseLocation让用户手动选择城市或区域然后从后台拉取这个范围内的科普场馆数据用markers标注到地图上。地图这一块我想提醒三点。第一wx.getLocation需要在小程序后台申请用户隐私授权而且要在app.json里声明requiredPrivateInfos字段否则接口调用会直接被拒绝。第二个人主体的小程序使用地图服务时最好选用腾讯位置服务和小程序配合度高文档也很全。第三markers的标注图标建议自己准备一个小图标的PNG默认的红色大头针虽然能用但和整个界面的风格不太搭。5.2 订阅消息不是推送而是“用户主动订阅后的服务”很多做小程序的朋友把订阅消息理解成App推送这是误解。微信小程序的订阅消息是一锤子买卖或者按次购买的用户点击授权后你才能给他发一条消息而且授权弹窗必须在用户主动触发的事件里调起不能在页面加载时自动弹。我在博物系统里做的是“新展品上线提醒”用户点击“订阅上新提醒”按钮调用wx.requestSubscribeMessage用户同意后我记录下这个授权后续通过云函数下发消息。实际开发中我踩过一个坑一次性订阅消息只能发一次用户订阅三次就只能发三条用完需要再次引导订阅。我一开始没注意测试时发完消息后第二次就发不出去了还以为是代码bug。后来改成在详情页里设置一个“再次订阅”的引导入口用户看完新内容后顺手点一下体验上比强制弹窗自然得多。订阅消息的模板ID也要提前在小程序后台申请审核通过后才能使用。5.3 云开发没有服务器的后端替代方案博物系统第一版没有自建服务器但收藏、订阅记录这类数据总得有地方存于是我用了微信云开发。云开发提供数据库、云函数、云存储对小项目来说基本够用。我的收藏功能是这样实现的用户在详情页点击收藏前端调用云数据库的collection.add把词条对象和用户openid一起存进去收藏列表页用get函数按openid查询openid通过云函数里的cloud.getWXContext()获取前端拿不到真正的openid这对隐私保护也更友好。云开发的免费额度对个人项目来说非常够用数据库的读写次数和存储容量我用到现在都没超。唯一要提醒的是云开发的环境ID要填对在app.js里初始化时wx.cloud.init({ env: your-env-id })如果env填错或者不填所有数据库操作都会报错。另外云函数每次更新后要记得重新部署本地测试通过不代表线上环境已经更新这个问题我至少犯过三次。6. 常见问题与踩坑实录6.1 顶部导航栏在不同机型上高度不一致博物系统上线后有用户反馈说在iPhone 13 Pro Max上页面顶部内容被刘海挡住了一点而在Android上又正常。这个问题的根源就是我前面提到过的navigationBar高度没有做适配。系统的导航栏在iPhone上会包含状态栏和胶囊按钮在Android上通常只有状态栏高度差异接近30rpx如果页面用固定定位的元素就非常容易错位。我的解决办法是写一个getNavBarInfo工具函数通过wx.getWindowInfo取到statusBarHeight再用wx.getMenuButtonBoundingClientRect获得胶囊按钮的位置和尺寸算出导航栏内容区的高度。在需要适配的地方用内联style动态设置paddingTop。这套逻辑封装好后所有页面统一调用没有再出现被遮挡的情况。如果你遇到类似问题先别急着改样式要确认是不是高度计算方式的问题。6.2 苹果手机上页面滚动卡顿的几个原因小程序在iOS上的滚动流畅度普遍比Android差一点但“完全滑不动”就是问题。我遇到过用户在苹果手机上无法滚动列表页的情况排查后发现是因为我给page或最外层view加了overflow: hidden加上内部元素高度计算不准确导致滚动事件被吞掉了。iOS的WebView对overflow的解析比Android严格一旦外层容器高度被限定内部滚动区域就不会触发。解决方法是把滚动容器放到page本身也就是说尽量用页面原生的滚动而不是自己用view装一个可滚动区域。具体来说不要在page里最外层套一个设了固定高度的view也不要给page加overflow: hidden。用页面原生的滚动虽然少了一些自定义下拉刷新的自由度但兼容性最好。如果你一定要自定义滚动容器请给容器设一个明确的高度值比如用calc(100vh - 导航栏高度)计算而不是auto或100%。6.3 真机调试连接失败与handshake failed报错有一次我在真机预览时扫码后开发者工具一直提示“handshake failed due to invalid upgrade header: null”查了好久最后定位到是电脑和手机连接的Wi-Fi网络环境问题。手机和电脑如果不在同一个局域网或者公司网络、校园网开启了AP隔离真机调试时设备之间无法建立连接就会出现这类WebSocket握手失败的报错。遇到这个问题先别怀疑代码按这个顺序排查手机和电脑连同一个Wi-Fi关掉电脑防火墙或在小程序开发者工具里设置网络白名单换一个手机热点试试。很多时候连手机热点最省事因为热点环境天然保证设备互通。另外开发者工具要使用“真机调试2.0”模式稳定的连接时间会稍微长一点但功能更全。如果你用的是模拟器一般不会遇到握手问题但模拟器上地图、相机这类原生能力是模拟不了的该真机调试时还是得到真机上验证。6.4 小程序包体积超限与图片压缩方案博物系统第一版做到一半时我遇到了一个很经典的瓶颈主包体积逼近2MB开发者工具直接警告“代码包超过限制”。我统计了一下绝大部分体积都来自图片。这里给一个自查清单第一页面本地图片控制在10张以内图标尽量用字体图标或者统一做成雪碧图第二详情页图片全部走远程URL不放本地第三JPEG图片尽量压缩到100KB以内PNG图片用在线工具压缩后再使用。压缩图片我推荐两个工具TinyPNG对PNG和JPEG的压缩率都很高肉眼基本看不出画质损失SquooshGoogle出品可以在线调整图片的尺寸和压缩率对小图片特别友好。图片资源问题处理完后我还清理了一遍HTML注释、未使用的样式和废弃页面包体积直接降到了1.2MB左右。这件事给我的启示是正式开发之前就要想好资源策略不要等包超限了再回头处理非常耽误进度。6.5 体验版发布前的自查清单小程序开发完不能立刻上线我总结了一份每次发体验版前都会过的自查清单。首先是后台配置确认服务器域名、downloadFile域名、uploadFile域名都配置正确且是HTTPS。其次是权限配置地图、订阅消息、相册保存等接口的隐私声明是否填写。然后是代码层面用开发者工具的“代码质量”检查一遍确认没有error级别的警告再用“真机预览”把核心流程跑一遍尤其是登录、支付如果有、收藏、搜索这几个核心操作。还有一个我每次都会做的检查在不同的手机和微信版本上测试。微信基础库的版本碎片化很严重有些用户微信长期不更新基础库还停留在两三年前新API在老基础库上会直接报错。我们可以在app.json里设置最低基础库版本低于这个版本的用户打开小程序时会看到升级提示。这个设置我在开发初期就配好了否则用户侧出现兼容问题后再处理排查成本要高得多。最后再分享一个小技巧每次发布新版本我都会先发体验版让身边的朋友帮忙在真实场景里用几天收集一轮反馈再提交审核。体验版和正式版功能一致但不需要等待审核非常适合快速验证想法。这个小习惯帮我提前发现了不少自己测不出来的问题比如某些安卓机型的图片加载异常、部分用户搜不到词条关键词等等对个人开发者来说特别实用。关于博物系统的第一篇开发日记就先写到这里下一篇我会重点讲内容运营和用户体验优化包括怎么批量整理词条、怎么设计更友好的收藏列表、以及怎么让首页推荐更贴合用户兴趣。希望这些踩坑经验和实操细节能对你的小程序开发有所帮助。