ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

微信小程序期末作业实战:从零开发一个简单日记小程序

2026/8/27 22:56:36 拓冰建站 浏览量
微信小程序期末作业实战:从零开发一个简单日记小程序 简介微信小程序开发是当前前端工程领域的热门技能而数据持久化与页面生命周期管理则是绕不开的核心基础。在本地存储Storage机制下开发者可以通过增删改查操作构建完整的业务闭环并深刻理解页面渲染与数据同步的底层逻辑。一个功能简洁但结构完整的日记小程序恰好能承载这些关键技术点利用 wx.setStorageSync 实现本地数据读写通过 onShow、onLoad 等生命周期函数处理页面刷新借助 setData 完成视图更新。这种轻量级项目不仅适合大学生期末大作业也是入门小程序开发的高效实践路径。本文以“简单日记小程序”为例完整拆解从需求梳理、原生开发到答辩准备的每一个环节并针对数据不刷新、长列表性能、真机白屏等高频问题给出排查方案帮助开发者快速构建一个可演示、可扩展的工程项目。1. 项目概述与需求拆解1.1 为什么选“简单日记小程序”作为期末大作业每年期末微信小程序开发课的收官任务都让不少同学头疼。选电商项目后端接口和支付流程能把人绕晕选工具类项目又容易做得像交差。我自己当年带过不少毕业生和实习生也帮人看过几十份期末作业最推荐的选题恰恰就是这类“功能看似简单、但五脏俱全”的日记小程序。原因很简单期末大作业的评审逻辑通常不是看你的功能多炫而是看你能不能把“增删改查”这一整套业务闭环跑通并且代码结构清晰、界面可用。日记小程序的本质就是围绕“数据”做一套完整的持久化操作——新增、编辑、删除、列表展示、日期筛选这正好覆盖了小程序开发中最核心的知识点页面生命周期、数据绑定、条件渲染、列表渲染、本地存储读写、事件处理。把这些吃透比堆砌十几个华而不实的页面要实在得多。再说直白一点这类项目的数据结构足够简单。日记的核心字段无非就是标题、正文内容、创建时间、更新时间这几个不需要设计多张关联表也不依赖后端接口。这就意味着你可以把全部精力放在“小程序本身”上而不是在服务端环境配置里耗掉大半时间。对于一周到两周的期末冲刺周期来说这个投入产出比非常划算。1.2 期末评分视角下的“产品定位”很多同学做作业容易陷入一个误区把“能跑”当成“完成了”。但老师评分的视角和你不一样他更看重的是你有没有做出“健壮性”。比如空数据时页面长什么样、用户删除日记时有没有二次确认、编辑之后列表有没有及时刷新、日期格式是不是按中国习惯显示。这些都是拉开分数差距的细节。我把这套日记小程序定位成“单机版、本地存储、快捷记录”的轻量工具。不依赖服务器不引入云开发所有数据存进微信小程序的 Storage。好处有三点一是演示时不怕断网掉链子二是代码全在前端逻辑一目了然答辩时好解释三是本地存储的读写速度快界面响应非常跟手。目标用户也很清晰课程老师 答辩评委。所以UI要做到干净、整齐操作路径要短。我见过不少同学把页面堆得很满按钮放得到处都是反而显得业余。日记类工具的界面克制是最重要的一个输入页、一个列表页、一个详情页足够了。2. 整体设计思路与技术选型2.1 页面结构与交互流程设计整个小程序我规划了三个核心页面首页日记列表页负责展示所有日记的摘要按时间倒序排列支持点击进入详情也支持长按删除。编辑页承担“新建”和“修改”两种职责。通过接收不同的参数区分是新增还是编辑保存时统一走同一个入库函数。详情页展示完整日记内容提供“编辑”“删除”两个入口底部显示创建时间和最后修改时间。页面之间的跳转关系是这样的首页 → 编辑页新建首页 → 详情页 → 编辑页修改编辑页保存后返回上一页同时触发上一页的列表刷新。这里需要用到一个关键APIwx.navigateBack配合页面onShow生命周期里的数据重新拉取保证每次从编辑页返回列表时数据都是最新的。底部导航我没有做 TabBar因为日记工具的页面层级本来就是“首页 → 二级页”的树形结构不需要并列的 tab。真要做 TabBar反而要考虑首页列表和搜索页之间的数据同步问题复杂度会上去一截。对期末作业来说页面层级越简单演示越流畅答辩越不容易被问倒。2.2 为什么坚持用“原生小程序”而非框架这个决策我是很坚持的。现在网上铺天盖地的模板都是 uniapp 或者 Taro 写的语法确实贴近 Vue上手觉得爽。但期末答辩时老师大概率会翻你的源代码问你这个指令对应底层做了什么。如果你用 uniapp他可能问“v-model 在原生里是怎么实现的”“uniapp 的编译链路是什么样的”这些问题如果你没深入过很容易卡壳。原生小程序的语法体系虽然啰嗦一点但胜在透明。WXML 就是标签WXSS 就是样式JS 就是逻辑JSON 就是配置。每一行代码都能找到对应的官方文档每一个 API 调用都能直接对应到运行时的行为。我用原生语法写这套日记小程序核心代码量控制在 500 行以内逻辑直观注释清晰老师翻代码的时候会感觉非常舒服。另外还有一个非常现实的原因微信开发者工具对原生项目的调试支持最完整。从 Storage 的可视化查看到页面栈的追踪都能在工具里直接完成。这对期末阶段的反复调试来说效率比任何框架都高。2.3 数据存储方案从 Storage 到预留云开发数据全部存本地 Storage用wx.setStorageSync和wx.getStorageSync完成同步读写。Storage 的本质是给每个小程序分配一个独立的本地存储空间最大容量有 10MB 的限制。对日记这种纯文本数据来说假设一篇日记平均 500 字大概 1KB10MB 差不多可以存一万篇期末演示绰绰有余。但为了答辩时能“拔高”项目层次我在代码里预留了一个数据访问层。简单说就是封装了getDiaryList、saveDiary、deleteDiary三个函数页面里所有操作都走这三个函数而不是直接去碰 Storage 的 API。这样如果老师问“如果以后要上云端怎么办”你可以很自然地回答“我把数据层做了隔离后续接入云开发数据库时只需要重写这三个函数的内部实现页面代码完全不用动。”这个“数据访问层”设计虽然只有十几行代码但体现的是架构意识。在小程序这种小体量项目里这种意识比会调 API 更值钱也是答辩的加分点。3. 核心功能实现与技术要点3.1 日记数据结构的定义与初始化在项目的utils/diary.js里我定义了一套统一的数据结构所有的日记对象遵循这个格式// 日记对象结构 { id: number, // 唯一标识使用时间戳生成 title: string, // 日记标题可为空为空时自动取正文前10个字 content: string, // 正文内容 createTime: string, // 创建时间格式 yyyy-MM-dd HH:mm updateTime: string // 最后修改时间格式 yyyy-MM-dd HH:mm }这里有一个比较容易忽略的坑id不能用自增数字因为删除日记后自增序列会乱而且本地存储里自增要额外维护一个计数变量太绕。最稳妥的方式是用Date.now()生成 13 位毫秒时间戳作为 id。同一毫秒内创建两条记录的概率在日记场景下几乎为零即便真撞了也可以补个随机数后缀。初始化数据的代码我放在app.js的onLaunch里首次启动时往 Storage 里塞一两条示例日记。这有一个很实际的好处演示时打开小程序就能看到内容不用现场敲字。不然老师盯着你输入半天体验很差。// app.js 片段 onLaunch() { const list wx.getStorageSync(diaryList); if (!list || list.length 0) { const seedDiary { id: Date.now(), title: 欢迎使用日记小程序, content: 这是一篇示例日记点击右下角按钮可以新建日记长按列表项可以删除日记。, createTime: this.formatTime(new Date()), updateTime: this.formatTime(new Date()) }; wx.setStorageSync(diaryList, [seedDiary]); } }formatTime这个函数我单独抽到了utils/util.js里因为在页面中多处都要用到时间格式化。它的实现并不复杂核心逻辑是用getFullYear、getMonth1、getDate等 API 拼字符串注意月份要加 1这是新手最容易写错的地方。3.2 首页列表渲染与空态处理首页的列表是所有功能的入口。WXML 里用wx:for循环渲染日记卡片每一张卡片展示标题、内容摘要和创建日期。摘要内容我做了截断处理超过两行就用 CSS 的text-overflow: ellipsis省略而不是在 JS 里去切字符串这样更灵活也保留了原文的完整性。列表按创建时间倒序排列用Array.prototype.sort比较createTime字符串即可。因为时间格式是加了前导零的yyyy-MM-dd HH:mm按字符串排序的结果和时间顺序完全一致不需要转成时间戳再比这个技巧能少写好几行代码。空态处理是我特别强调的。当 Storage 里没有任何日记时页面不能显示一个光秃秃的白屏要有一张居中的插图和一行提示文案“还没有日记点击下方按钮开始记录吧”。空态的作用不只是好看更重要的是引导用户完成下一步操作。这种细节老师一眼就能看出来你是有产品思维还是单纯的代码搬运工。卡片点击跳转详情页时通过 URL 参数传递日记 id// 列表页跳转 goDetail(e) { const id e.currentTarget.dataset.id; wx.navigateTo({ url: /pages/detail/detail?id${id} }); }详情页在onLoad里接收参数再从完整的日记列表中find出对应的对象。这里要提醒一点从wx.navigateTo传来的参数都是字符串类型所以id比较时要么用转义后的数字比较要么就用String()统一类型。用松散比较虽然能处理但期末答辩时被问到“双等号和三等号的区别”会很尴尬直接全用严格等于比较规范。3.3 编辑页新建与编辑的双重身份编辑页是这套小程序里逻辑最密集的页面。它既要处理新建又要处理编辑所以需要根据onLoad里有没有收到id参数来区分收到id说明是编辑模式需要从 Storage 里把原数据读出来回填到表单里。没收到id说明是新建模式表单初始化为空。WXML 里的输入控件我用textarea做正文、input做标题。这里有一个很重要的属性配置textarea的maxlength不要设成 -1无限建议默认 140 或 500。我设的是 500够写一篇小日记也不会让数据体积失控。同时配合一个实时字数统计“剩余 xxx 字”用bindinput事件监听输入更新剩余字数。保存逻辑我写在一个save方法里处理内容包括save() { const title this.data.title.trim(); const content this.data.content.trim(); if (!content) { wx.showToast({ title: 内容不能为空, icon: none }); return; } const finalTitle title || content.slice(0, 10); // 判断编辑或新增 if (this.data.id) { // 编辑更新对应记录 } else { // 新增push 新记录 } wx.setStorageSync(diaryList, newList); wx.navigateBack(); }标题为空时自动截取正文前十个字作为标题这个小细节是我个人很喜欢的既省了用户手动填标题的步骤又保证列表页不会出现“无标题”这种尴尬情况。content.slice(0, 10)这里我直接用字符串方法不涉及中英文字符差异因为 JavaScript 的slice是按 Unicode 码点切的中文不会有问题但要注意如果截取到半截 emoji 可能出现显示异常日记场景基本不影响。编辑页还有一个体验细节正文输入框要设置auto-height或固定高度并配合cursor-spacing属性这样键盘弹起时不会被遮挡。cursor-spacing的作用是控制输入光标与键盘上边缘的距离我设的是 20px实测效果不错。这个属性很多同学不知道答辩时能说出来是一个加分项。3.4 详情页的时间展示与操作入口详情页是信息展示为主核心元素包括大标题、创建时间、更新时间、完整正文、底部操作栏编辑按钮 删除按钮。时间展示我用了两块并排的布局看起来像产品详情页的规格参数一眼就能看出信息的层次感。在 WXML 里直接用{{diary.createTime}}输出字符串不需要再做任何格式化处理因为数据入库时就已经是标准格式了。删除操作做了二次确认弹窗用wx.showModal实现deleteDiary() { wx.showModal({ title: 提示, content: 确定删除这篇日记吗删除后不可恢复。, confirmColor: #e64340, success: (res) { if (res.confirm) { const list getDiaryList().filter(item item.id ! this.data.id); saveDiaryList(list); wx.navigateBack(); } } }); }confirmColor我特意设成了红色系通过视觉暗示这个操作是风险操作。这个细节在用户研究里叫“操作可见性与反馈一致性”虽然听起来高大上但本质上就是让人一眼看懂“这个按钮不能乱点”。编辑操作直接wx.redirectTo跳转到编辑页并带上当前日记的 id。用redirectTo而不是navigateTo是因为详情页完成任务后就没有保留的必要了不让页面栈里堆积无用页面也避免用户从编辑页返回时又看到详情页的重复路径。4. 开发环境配置与踩坑记录4.1 AppID 的选择与项目初始化期末阶段大部分同学没有注册小程序账号这里有一个非常实用的选择微信开发者工具支持“测试号”在新建项目时选择“测试号”即可免注册 AppID所有核心 API 都能正常使用。区别仅在于测试号无法真机预览、无法上传发布但对纯本地存储的日记小程序来说模拟器上完全够用。如果你已经注册了个人小程序账号流程很简单去微信公众平台用邮箱注册就行建议直接用真实 AppID。好处是可以用手机真机预览测试键盘弹起、触摸滑动等模拟器上无法完全模拟的交互。真机调试时记得在工具里打开“开发环境不校验请求域名”虽然本项目没有网络请求但这是通用习惯顺手就要勾上。项目初始化时模板选择“不使用模板”就好用空白目录建项目。新建完成后我习惯先把app.json的window配置调好——导航栏标题设为“简单日记”、背景色设为白色、导航栏文字颜色设为黑色。这些基础配置看着简单但直接影响第一印象。4.2 开发者工具中的调试技巧与日志定位微信开发者工具的控制台是期末项目最重要的调试阵地。我在每个核心函数里都留了console.log输出比如保存成功时打印[diary] save success, list length xxx。表面上看多打几行日志无所谓但调试时能大幅缩短定位时间。Storage 面板是非常好用的可视化工具。在“调试器 → Storage”标签页里可以直接看到diaryList这个 key 的全部数据甚至可以手动编辑或删除某条数据来模拟异常场景。测试空态显示效果时我就是在 Storage 面板里把diaryList直接置空一步到位不用先把所有日记删光。还有一个测试技巧用“编译模式”快速进入指定页面。默认编译是进入首页如果我在调试编辑页每次都要首页 → 新建 → 输入 → 保存非常浪费时间。通过在“普通编译 → 添加编译模式”里设置启动页面为pages/edit/edit并附上参数idxxxx就能一键直达编辑状态效率提升非常明显。4.3 模拟器与真机表现不一致的排障思路日记小程序虽然没有网络请求但还是会遇到一些环境差异问题。最典型的是键盘弹起时的页面表现。模拟器里点输入框键盘区是模拟的不会遮挡页面但真机上键盘会实实在在地弹起来如果没有处理好输入框会被挡掉很大一块。解决方案就是前面提到的cursor-spacing属性另外还可以给页面adjust-position设 false、自己手动onKeyboardHeightChange调整但日记项目用cursor-spacing就够。另一个真机差异是页面滚动的回弹效果。模拟器上滚动到底部很干脆真机上会有橡皮筋效果这是 iOS WebView 的默认行为不用管它属于正常的系统交互。但如果你在详情页发现内容上下弹动很突兀检查一下page的高度设置确保min-height: 100vh而不是固定height: 100vh否则内容超出一屏时滚动会有问题。时间格式化在真机上还有一个隐藏的坑iOS 对new Date(2023-06-01 10:00:00)这种带横杠和空格的字符串解析支持不稳定在某些版本中会返回Invalid Date。写formatTime函数时要注意传入的 date 对象如果来自字符串最好先手动解析成年月日时分秒而不是直接塞给new Date。我在项目里的所有时间都是自己格式化生成的不走new Date逆向解析绕开了这个坑。5. 常见问题排查与避坑经验5.1 数据不刷新onShow 与 onLoad 的时机陷阱这是期末项目中频率最高的问题从编辑页保存返回首页列表却没有更新。原因在于onLoad只在页面首次加载时执行一次从编辑页返回属于“从二级页回退”首页本身已经在页面栈里活着不会重新触发onLoad。所以要在首页的onShow里重新拉取 Storage 数据并setData到页面上。// 首页 onShow() { this.loadDiaryList(); }这个问题的本质是“页面生命周期事件的选择”。onLoad适合做一次性初始化onShow适合做每次回显时的数据同步。我在一开始写的时候也没意识到第一次测试时发现列表不更新愣是查了半天代码最后才想起onShow这回事。写这篇博文的时候特意强调大家千万不要在这个地方浪费一晚上。5.2 长列表性能问题setData 的批量更新策略如果期末作业里你测试时录了上百条日记可能会发现列表偶尔掉帧。这个问题的根源在于setData是“全量更新”机制每次调用都会把数据从逻辑层传到渲染层数据量越大开销越大。优化方案有三种在onShow拉取数据后先做切片只渲染最近 30 条。给wx:for的每一项加上wx:key让渲染层可以精确复用节点而不是全部重建。对于超过一定条数的列表用onReachBottom触底分页加载每次追加 20 条。我在项目里用的是“数据切片 wx:key”双保险。切片的逻辑很简单getDiaryList().slice(0, 30)想偷懒的话甚至可以不做分页直接保证单次渲染的数据量足够小。这个优化在期末演示时评委不太会注意但它体现的是工程能力写进答辩 PPT 里很有面子。5.3 重复保存与快速点击的问题快速连续点击保存按钮会产生两条相同内容的日记。这个问题的根因是“事件触发频率高于业务逻辑的执行速度”。我的处理方式是加一个“保存锁”进入保存函数后先检查isSaving标记如果为 true 就直接 return否则置为 true保存完成后释放。save() { if (this.data.isSaving) return; this.setData({ isSaving: true }); // ... 保存逻辑 this.setData({ isSaving: false }); wx.navigateBack(); }同理列表项的点击跳转也可以加“防抖”避免手滑连续点两次进两个页面。通用做法是在跳转函数里设一个this.isNavigating标记跳转后立即置 true页面onHide或onUnload时再复位。这些细节跟工作里接触到的“防止重复提交”是一个思路提前在小程序里体会一遍以后做后台系统时会很有感触。5.4 真机预览时白屏的排查流程真机预览出现白屏是每个开发者迟早会遇到的事。我按优先级整理了一份排查清单先看手机端调试面板的 Console有没有报错。最常见的是渲染层报xxx is not defined通常是 WXML 里引用了不存在的变量名。看app.json里注册的页面路径是否和实际文件路径一致。路径不一致时工具会直接报编译错误但有时不会被留意一直点“预览”导致白屏。清掉小程序缓存再重新预览。开发者工具改过代码后偶尔会有缓存残留手机端也有缓存删掉小程序再重新扫码是最粗暴但有效的方案。检查 WXML 里是否写了无法解析的属性。比如自定义组件标签的properties里用了Object类型但没有给默认值渲染层拿到的可能是undefined导致崩溃。日记小程序结构简单白屏概率不大但万一出了别慌按顺序查下来肯定能定位。5.5 系统全面的常见问题速查表现象可能原因解决方案列表不更新在onLoad里拉数据onShow未触发把拉数据逻辑移到onShow保存后返回首页数据丢失wx.setStorageSync传入的 key 不一致统一封装saveDiaryListkey 常量统一管理日期显示为NaN-NaN-NaNiOS 下new Date解析字符串失败避免用字符串转Date手动拼格式键盘遮挡输入框未设置cursor-spacing输入框增加cursor-spacing20删除无反应二次确认弹窗的success回调里没清数据在success中判断res.confirm后执行删除真机白屏页面注册路径错误或代码报错查编译日志 删缓存重新预览输入内容长页面卡顿没做数据切片列表slice截取数据 分页加载6. 答辩演示准备与项目进阶建议6.1 演示脚本与操作路径规划期末答辩现场容易紧张一紧张就会手忙脚乱点错按钮、操作顺序混乱。我的建议是提前准备一份“演示脚本”把核心操作路径固定下来打开小程序停 3 秒让老师看清示例日记的展示效果口播“这是本地存储的日记列表按时间倒序排列。”点击新建输入标题和正文保存。返回列表指出刚才新写的日记出现在最顶部“这个交互依赖首页的 onShow 生命周期完成数据刷新。”点击刚写的日记进入详情再点编辑修改标题保存。返回列表后长按一条日记删除走完二次确认弹窗。最后展示空态把列表数据清空刷新页面演示“空数据引导”。这套流程走下来把增、删、改、查、空态全部覆盖全程 3 分钟搞定。每一步都能对应到一个知识点老师怎么提问你都有话可接。6.2 从期末作业到可上线项目的两个方向如果你学有余力想在期末作业基础上继续扩展我推荐两个方向第一个方向是“加云开发”。把数据从本地 Storage 迁移到微信云开发的数据库实现多设备同步。这个升级的改动量不大因为我在项目里已经做了数据访问层只需要重写getDiaryList、saveDiary、deleteDiary三个函数内部的具体实现页面的调用代码一行都不用改。改用云开发后还能顺手加一个“用户登录”用wx.openUserProfile或手机号快捷登录项目的完整度立刻上升一个档次。第二个方向是“加 AI 能力”。现在小程序云开发已经支持云函数调用大模型 API可以在编辑页放一个“一键润色”按钮调用云函数把日记内容发送给大模型生成润色版本。这个功能看起来高端实际实现起来也不算复杂核心就是云函数里发一个 HTTP 请求的事。期末能做出这个基本上是满分级的存在。6.3 答辩高频问题与应答参考老师可能会问建议回答思路数据存在哪里有什么限制存在本地 Storage上限 10MB适合轻量数据已预留数据访问层可平滑迁移到云开发为什么用时间戳当 id避免自增 id 在删除后冲突时间戳全局唯一生成成本低列表的性能如何优化数据切片 wx:key复用 触底分页Storage 和全局变量的区别Storage 持久化App 的 globalData 是内存态小程序杀进程后会丢失后期如何支持多端小程序的逻辑层已经和渲染层分离可以借鉴 Taro/uniapp 做编译适配但需要重构页面代码7. 总结我个人的一点实操体会这套日记小程序完整做下来我自己最大的体会是小项目才是练基本功的地方。字段设计、生命周期管理、数据流向、异常处理这些在大项目里会被各种框架和组件稀释掉的东西在几百行的小程序代码里反而被放大得很清晰。你写的每一行代码都能在微信开发者工具里立刻看到反馈这种正反馈循环对学习非常有效。最后再分享一个小技巧给项目写一份简短的README.md把自己的项目结构、核心文件、启动方式、踩过的坑都记下来。期末答辩时这份文档可以直接作为项目说明书的底稿平时自己回看也能快速回忆整个开发脉络。很多同学修完 bug 就结束了但我建议你多花半小时整理一下这个习惯在工作以后会受益很久。如果你照着这篇文章的思路把项目做完一定能交出一份能进优秀作业名单的期末作品。如果开发过程中遇到具体问题欢迎在评论区留下报错信息我会尽量帮你排查。本文还有配套的精品资源点击获取