从一行代码到微信小程序上线:一颗孤独星球的故事
- 2026-09-24 08:27:47
一位大学班主任、一个从零搭建的开源项目、7 种情绪颜色、无数个深夜改 bug —— 送给每一位曾在深夜里,不知道把心情放在哪里的你。
2026 年 8 月 3 日晚上 8 点 07 分,我坐在电脑前,手指悬在鼠标上,深吸一口气,点击了那个绿色的按钮——「提交发布」。
屏幕弹出一行字:「线上版本 1.0.2 发布成功」。
我瘫在椅子上,盯着天花板发了很久的呆。
此刻,距离 6 月 20 日我在 GitHub 和 AtomGit 上提交第一行代码,仅仅过去了 44 天。

一颗孤独的星球
故事要从一个偶然的想法说起。
我本职是一名大学老师,教《物流学》和《采购管理》,同时也是班主任。写代码纯粹是业余爱好。
这个身份很特别。作为班主任,我每天和学生打交道,越接近他们,越能意识到一件事:这群年轻人总会遇到形形色色的情绪问题。 考试前的焦虑、和室友闹矛盾后的低落、对未来的迷茫、说不清道不明的孤单……他们不是不想找人倾诉,而是不知道怎么说、跟谁说。
我见过一个平时很开朗的学生,连续几天蔫蔫的,后来才知道是在实习面试中屡屡碰壁;也见过一个成绩很好的学生,因为一次小组合作被误会,一个人坐在操场边发呆。
这些画面让我反复想一个问题:有没有一种方式,不需要开口,不需要解释,就能让自己的情绪被"看见"?
有一天,我脑子里冒出一个念头:能不能做一个简单的网页,让人选择一种情绪,就能看到一颗对应颜色的"星球"在屏幕中央缓缓旋转?
想法很简单,说干就干。几天后,一个单文件的 HTML 网页诞生了——深空背景、柔和的光晕、漂浮的颗粒,你选开心,它就是一颗金色的星球;你选难过,它变成紫色,给沉默的情绪一个看得见的形状。
我在 GitHub 和 AtomGit 上创建了仓库,把它开源发布出去,起了个名字叫 EmotionalPlanet——情绪星球。
双击打开亲手创作出来的网页,看着那颗淡蓝色的星球在屏幕上安静地旋转,我有了一种奇妙的感觉:好像那些说不出口的情绪,终于有了一个可以安放的地方。
但很快我就发现了一个问题:它只能一次性使用。刷新页面,星球就消失了。昨天的情绪、前天的情绪、一周前的情绪,全都找不回来。
而且它只能在电脑浏览器上打开。在这个人人手机不离手的时代,谁会特意打开电脑去记录心情呢?
如果它能变成一个微信小程序,每个人都可以随时随地打开,记录情绪、回顾成长,那该多好?
这个念头,像一颗种子,在我心里生了根。
从一行 HTML 到一个完整的小程序
如果你不是程序员,可以把下面这段话理解为:把一张手绘图纸,变成一栋可以住人的房子。
原来的 EmotionalPlanet 是我写的一个单文件网页——就像一张手绘图纸,画得很漂亮,但不能住人。要让它变成一个真正的微信小程序,我需要做三件事:
第一,把它拆成房间。 原来所有功能挤在一个大页面里,我把它们拆成了四个独立的"房间":一个欢迎大厅(首页)、一个心情记录间(记录页)、一个时光长廊(轨迹页)、一个成长报告厅(总结页)。每个房间各司其职,用户可以在它们之间自由切换。
第二,给每个房间装上门和窗。 在微信小程序的世界里,页面之间的切换不像网页那样随意。我设计了一套导航系统,让用户在底部就能一键切换,就像手机上熟悉的"发现-通讯录-我"那样自然。
第三,也是最难的——让房子有记忆。 原来的网页一关就忘了一切。我需要让小程序记住用户的每一次记录,但又不能让数据上传到任何服务器。这意味着所有的记忆都只能存在用户自己的手机里——就像一本只能在那部手机上翻看的日记本。
这就是我们选择的方案:纯本地存储。 你的情绪数据,只属于你自己。
七种颜色,七个宇宙
现在让我带你看看「情绪星球日记」到底长什么样。
打开小程序,你会看到一片深邃的太空。正中央,是一颗缓缓旋转的星球。它的颜色,取决于你上一次记录的心情。
我们一共设计了7 种情绪状态,每一种都对应一个独特的星球视觉:
如果你注意到,即使是最"负面"的情绪描述,结尾都有一个温柔的转折。这是我们刻意设计的——每一种情绪都值得被看见,也终将被安放。
代码里的温度
这一节写给对技术感兴趣的读者。如果你不是程序员,每个代码块后面都有"大白话拆解"的解读,不看代码也能感受到我们在做什么。
代码一:七种情绪的颜色配方
这是「情绪星球日记」最核心的"配方表"——7 种情绪,对应 7 种颜色,每一种都有独特的视觉设定。这些代码不是我从哪里复制来的,而是一个颜色一个颜色地调试、一个渐变一个渐变地观察,直到眼睛酸了才定下来的:
const emotions = {happy: { name: '开心', color: '#ffd060', desc: '阳光温暖,星球闪耀着金色光芒' },calm: { name: '平静', color: '#60c0e0', desc: '如湖水般宁静,星球泛着柔和蓝光' },sad: { name: '难过', color: '#8080c0', desc: '星球蒙上一层薄雾,但星光依然在' },angry: { name: '烦躁', color: '#e06050', desc: '星球表面涌动着红色岩浆,需要冷却' },love: { name: '感动', color: '#f080a0', desc: '星球绽放粉色光芒,温暖而柔软' },fear: { name: '焦虑', color: '#a070d0', desc: '星球被紫色迷雾环绕,深呼吸会好些' },surprise:{ name: '惊喜', color: '#50d0a0', desc: '星球突然亮起翠绿光芒,充满活力' }};大白话拆解:
#ffd060是一个"颜色代码",代表金黄色。用户选了"开心",星球就用这个颜色渲染;选了"难过",换成#8080c0(淡紫色)。注意看「难过」和「烦躁」的描述——即使是负面情绪,结尾都有一个正向的转折:"但星光依然在"、"需要冷却"。我们不是在美化负面情绪,而是在告诉用户:你此刻的感受是正常的,它终将过去。
代码二:让星球"活"起来
星球不是一张静态贴图。它会呼吸、会漂浮、光环会缓缓旋转。这些效果靠的就是几行 CSS 动画——你可以理解成"给星球写的动作指令":
.planet {animation: float 6s ease-in-out infinite, /* 上下漂浮,6秒一个周期 */ planetPulse 3s ease-in-out infinite; /* 呼吸明暗,3秒一个周期 */}.planet-ring {animation: ringRotate 20s linear infinite; /* 光环旋转,20秒一圈 */}@keyframes float { 0%, 100% { transform: translateY(0); } /* 起点和终点:不动 */ 50% { transform: translateY(-12rpx); } /* 中间:轻轻浮起12像素 */}@keyframes ringRotate {from { transform: rotate(0deg); } /* 从0度开始 */to { transform: rotate(360deg); } /* 旋转整整一圈 */}大白话拆解:这三组动画叠在一起,星球就"活"了——想象一个在水中轻轻浮动的气球:
float让它上下摆动,planetPulse让它像呼吸一样一明一暗,ringRotate让光环缓缓旋转。ease-in-out的意思是"慢—快—慢",所以星球的动作不是僵硬的机械摆动,而是像心跳一样,有节奏、有温度。
代码三:你的数据,只在你手里
这是整个项目最重要的设计决定。所有情绪记录都存在用户手机本地,不需要服务器:
// 保存记录:直接写入手机本地存储functionsaveEntries(entries) { wx.setStorageSync('emotion_planet_entries', JSON.stringify(entries));}// 读取记录:从手机本地读取functiongetEntries() {const data = wx.getStorageSync('emotion_planet_entries');return data ? JSON.parse(data) : [];}大白话拆解:
wx.setStorageSync是微信提供的一个存数据的方法。它把数据直接写进你手机的存储空间里——就像你在手机备忘录里写了一段话,只有你自己能看到。微信服务器看不到,我看不到,任何人都看不到。每次打开小程序,它只是从你手机里把以前的记录读出来。整个过程,没有任何数据离开过你的手机。
你记录得越多,星球就越强大
我们设计了一套7 级星球成长体系:
星尘 → 萌芽 → 幼星 → 行星 → 巨星 → 恒星 → 星系
当你第一次打开小程序,你的星球只是一粒微小的星尘。随着你一天天记录心情,星球会慢慢长大——变大、变亮、长出光环,直到成为一颗能照亮整个星系的恒星。
这不是一个游戏化的"积分系统"。这是一个隐喻。
每一次面对自己的情绪,都是在为自己的内心宇宙积蓄能量。
写到这里,我突然想到一句话,后来也写进了小程序的"本周总结"里:
"你今天记录下来的是心情,但回头看,那是你一步一步成长的路。"
踩过的坑,比写过的代码还多
如果这篇文章到此为止,那它只是一个产品介绍。但我真正想跟你分享的,是那些"差点就放弃了"的时刻。
坑一:WXML 里不能换行??
微信小程序的页面结构文件叫 WXML,它跟网页的 HTML 很像,但有各种"个性"。
有一天深夜,我把代码提交给微信审核,结果直接被打回来——因为星球组件的 WXML 文件里,style 属性的值不能换行。
这是什么概念呢?就像你写作文,老师突然说:"这句话太长,不能断成两行,必须一口气写完。"
而我们的星球组件有大量的样式代码,每一条颜色、光晕、位置参数,都和在一起变成了一行几百个字符的"长龙"。肉眼几乎无法维护。
解决方案:把所有样式计算逻辑提前处理好,在 JavaScript 里拼成一个完整的字符串,再传给 WXML。
// planet.js —— 把所有样式值提前算好,传给模板Component({properties: {planetColor: { type: String, value: '#ffd060' },planetBackground: { type: String, value: '#ffd060' },planetSize: { type: Number, value: 240 },glowColor: { type: String, value: 'rgba(255,208,96,0.4)' },glowSize1: { type: Number, value: 60 },glowSize2: { type: Number, value: 120 },showRing: { type: Boolean, value: false },ringSize: { type: Number, value: 240 },ringBorder: { type: Number, value: 3 },size: { type: Number, value: 400 },pulse: { type: Boolean, value: true } }});<!-- planet.wxml —— 模板只负责展示,不参与任何计算 --><viewclass="planet-stage"style="width: {{size}}rpx; height: {{size}}rpx;"><viewwx:if="{{showRing}}"class="planet-ring"style="width: {{ringSize}}rpx; height: {{ringSize / 4}}rpx; border-width: {{ringBorder}}rpx;"></view><viewclass="planet {{pulseClass}}"style="width: {{planetSize}}rpx; height: {{planetSize}}rpx; background-color: {{planetColor}}; box-shadow: 0 0 {{glowSize1}}rpx {{glowColor}}, 0 0 {{glowSize2}}rpx {{glowColor}}; background: {{planetBackground}};"></view></view>小Tips:不要在写作文的时候现场算数,先算好数字,再填进去。
坑二:总结页,一个隐形的幽灵 Bug
上线前一天晚上,我信心满满地点开总结页——白屏。空白。什么都没有。
控制台报了一堆红色错误。我盯着代码看了半小时,发现了一个很隐蔽的问题:当用户的记录数据处于某些"边界状态"时——比如只有一条记录、或者跨月份的记录——日期解析会崩溃。
更麻烦的是,在小程序里,很多在网页上好用的日期处理函数,根本不兼容。
解决方案:我把整个总结页的数据加载逻辑推倒重写。用了最"笨"但最可靠的日期处理方法——把年月日拆成数字,一个一个比对,不给任何"智能函数"出错的机会。
// summary.js —— 不依赖任何日期库,纯手工解析functionsafeDateStr(d) {const y = d.getFullYear();const m = String(d.getMonth() + 1).padStart(2, '0');const day = String(d.getDate()).padStart(2, '0');return`${y}-${m}-${day}`;}functionparseDate(str) {if (!str || typeof str !== 'string') returnnull; // 空值保护const parts = str.split('-');if (parts.length !== 3) returnnull; // 格式保护const y = parseInt(parts[0], 10);const m = parseInt(parts[1], 10) - 1;const d = parseInt(parts[2], 10);const date = newDate(y, m, d);if (isNaN(date.getTime())) returnnull; // 非法日期保护return date;}// 计算本周范围,兼容跨月、周日为一周起点的场景functiongetThisWeekRange() {const now = newDate();const dayOfWeek = now.getDay();const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;const monday = newDate(now.getFullYear(), now.getMonth(), now.getDate() + mondayOffset);const sunday = newDate(monday.getFullYear(), monday.getMonth(), monday.getDate() + 6);return { start: safeDateStr(monday), end: safeDateStr(sunday) };}小Tips:我不再依赖任何"智能工具"来自动理解日期,而是像查字典一样,年、月、日一个一个拆开比对。同时给三个最容易崩溃的地方各套了一层"安全网":空值、格式错误、非法日期。
这一改,改到凌晨一点。
坑三:隐私保护指引 —— 比代码还难写的东西
代码审核通过了,但我遇到了一个意想不到的关卡:隐私保护指引审核不通过。
原因是我对"选中的文件"这个接口的用途说明写得太笼统了。微信审核要求每个权限都要有明确、具体、符合实际使用场景的说明。
改了三次,最终写成了最直白的说法:
"用于读取用户选择的本地备份文件,恢复历史心情记录"
"用于导出心情记录数据到剪贴板,便于用户备份"
一次通过。
经验教训:跟审核打交道的秘诀就是——真诚、直白、不要玩概念。
坑四:从 0 到 1,鸿蒙原生应用
微信小程序上线后,我又做了一件"自虐"的事情:把整个项目用华为鸿蒙的 ArkTS 语言重写了一遍。
这意味着什么?意味着所有的代码、所有的页面结构、所有的数据存储方式、所有的动画效果——全部要在一个全新的语言和框架里重做。
其中最折腾的是星球动画。在微信小程序里,星球的光环旋转、脉冲呼吸、漂浮移动,靠的是 CSS 动画——简单、成熟、资料多。
/* 微信小程序:CSS 三行搞定 */@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); }}.planet-stage {animation: float 3s ease-in-out infinite alternate;}但在鸿蒙的 ArkTS 里,没有 CSS,一切动画都需要用代码逐帧控制:
// 鸿蒙 ArkTS:相同的效果,需要手写动画函数private startFloatAnimation(): void { animateTo({ duration: 3000, curve: Curve.EaseInOut, iterations: -1, // 无限循环 playMode: PlayMode.Alternate // 来回播放 }, () => {this.translateY = -6; // 向上浮动 6 像素 });}// 光环旋转:两万毫秒转一圈private startRingAnimation(): void { animateTo({ duration: 20000, curve: Curve.Linear, iterations: -1 }, () => {this.ringAngle = 360; });}打个比方:在微信里,你告诉星球"你自己转吧,速度是每分钟一圈",星球就自己转了。在鸿蒙里,你需要每秒告诉星球"现在转到这个角度,0.01 秒后转到那个角度……"
但最后,当我在鸿蒙模拟器上看到那颗熟悉的星球再次缓缓旋转时,所有的折腾都值了。

为什么这是一件"公益"的事
写到这里,你可能想问:你折腾了这么久,赚了多少钱?
答案是:零。
这个小程序没有广告、没有付费功能、没有收集任何用户数据。我甚至刻意去掉了所有"AI"的字眼——不是因为 AI 不好,而是因为一旦声明了 AI,审核就要求你去做算法备案,而这个流程对于个人开发者来说,门槛太高了。
我们用的情绪回复功能,其实是用最传统的关键词匹配实现的——你的日记里出现"考试"、"成绩",它就会温柔地安慰你。没有大数据模型,没有云端计算,一切都在你的手机上完成。
这不是什么高深的技术,但它有一个无法替代的优点:它不会把你的心事上传到任何地方。
在这个数据比黄金还贵的时代,让用户的情绪留在用户的手机里——这件看似"不聪明"的事,恰恰是我们最想守护的东西。
致敬每一位创造者
回到那个坐在电脑前的深夜。
我并不是一个全职开发者。我是一名大学老师。编程对我来说,是业余爱好。写代码的过程充满了"为什么这样不行?"、"刚刚还好的,怎么又坏了?"、"这个报错是什么意思?"(然后去搜 N 分钟/小时)。
但也是在这个过程中,我体会到了一种很纯粹的东西:
当你看到一行丑陋的代码,慢慢变成一颗会旋转的、会发光的、会成长的星球——那种创造的感觉,和赚钱、名声、任何外在的回报都无关。它是一种很纯粹的满足感。就像一个孩子用积木搭了一座城堡,虽然歪歪扭扭,但那是他自己的城堡。
我希望「情绪星球日记」能成为一个温暖的存在。不是因为它技术有多牛,而是因为它在意。
在意每一个在深夜辗转反侧的人;
在意那些说不出口的开心和难过;
在意那些微小的、普通的、却又无比真实的情绪瞬间。
写在最后
如果你愿意,现在就可以在微信里搜索「情绪星球日记」,找到那颗属于你的星球。

它是免费的,没有广告,不上传数据。
你写下的每一句话,都只存在你自己的手机里。
就像每个人的内心宇宙,终究只属于自己。
但我们依然可以透过星光,远远地看见彼此。
大卡
开发者
落笔于情绪星球日记 1.0.2 上线的夜晚