独立开发实战:我用 AI 写了一个台球小程序

作为一名既爱写代码又爱打台球的程序员,我一直想做一款"纯粹"的台球工具。市面上的 App 要么广告满天飞,要么功能单一------能计分的不能复盘,能复盘的体验太差。

于是,我决定自己造个轮子。完全根据我自己需要来定制化开发。

这款名为**"追分记"的小程序,不仅支持中式黑八/九球的复杂计分(断点续打、三人追分)、自定义训练模式(统计五分点等训练记录),还内置了一个基于物理交互的战术板**。

这篇文章我将从产品构思、AI 辅助设计、本地存储架构等维度,复盘这次独立开发的完整过程。

一、 从构思到落地:AI 如何加速全流程

在这次开发中,我尝试了一种新的工作流:全程 AI 开发。从灵感到 UI,再到代码落地,让AI 扮演"产品助理"、"UI 设计师"、开发工程师的角色。

1.1 需求构思:解决我自己的痛点

在写第一行代码前,我先整理了自己的"吐槽清单":

  • 痛点 A:打九球追分,算大金、小金、犯规扣分太烧脑,容易算错。
  • 痛点 B:打到一半朋友来电话,切出去回个消息,回来小程序重载了,比分全丢。
  • 痛点 C:想给朋友讲刚才那杆球怎么走位,手边没球桌,干讲听不懂。
  • 通点 D:自己平时去训练,也不知道训练的目标和效果。

基于此,确定了 MVP(最小可行性产品)的三大核心功能:智能计分器、断点续打系统、便携战术板

1.2 AI 生成 产品初稿,再生成 UI:从 Prompt 到视觉稿

作为程序员,配色和 UI 往往是短板。这次我没有自己瞎折腾 CSS,而是利用 AI 生成设计灵感。

从一个新的项目开始,我让 Trae 帮我生成一个完整prd文档,包含需求分析,功能模块,页面细节。

然后让它开始实现这些功能,然而最后实现的UI界面效果很不理想。

于是,我把这个截图扔给 v0v0.app/),让他按照这个截图的哪内容帮我从新生成一个页面UI,并且产出一个完整的配色,以便其他页面复用。提示词如下:

你现在是个专业的UI交互设计师,帮我优化一下这个页面的UI,然后生成一个静态的html。不允许使用tailwind css,图标库可以使用lucide。需要生成一个完整的配色方案。

最后它帮我产出了一个html文件,我打开一天,天啦,这也太牛逼 plus了。

这效果已经超出我的想象了。于是我立马让 Trae 把这个页面1:1还原到对应的小程序页面。

提示词:根据 index.html 1:1还原 index.wxml 的UI。注意: index.htm 通用的root样式可以提取到公共样式中进行复用。

拿到视觉基调后,我将其转化为全局 CSS 变量(app.wxss),确保全站风格统一:

css 复制代码
page {
  --bg-primary: #0a0f1a;
  --text-primary: #f8fafc;
  --accent-green: #10b981;
  --card-bg: rgba(30, 41, 59, 0.7);
  background: linear-gradient(160deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
}

从最初简陋的线框图,到引入 tdesign 组件库,再到配合 AI 生成的图标,产品的"颜值"经过了三轮大的迭代,最终呈现出一种"极客范儿"的精致感。

业务逻辑和UI进行了完美的融合,没有任何bug。简直完美。


二、 核心技术复盘 II:本地存储的"垃圾回收"机制

做"断点续打"功能时,我遇到了一个典型问题: 用户可能开了局,没打完就退出了;过几天又开了新局。久而久之,Storage 里会堆积大量废弃的比赛快照(Snapshot)。

为了解决这个问题,我设计了一套基于索引的 GC(垃圾回收)机制

3.1 存储结构设计

  • 索引表 (ongoingMatches):记录所有"进行中"比赛的元数据(ID、时间、模式)。
  • 快照数据 (match_current_{id}):每场比赛的具体状态单独存一个 Key,防止单条数据过大。

3.2 自动 GC 实现

每次小程序启动或进入列表页时,触发 cleanupOrphans 函数:

javascript 复制代码
// utils/storage.js
function cleanupOrphans() {
  // 1. 获取"存活"的比赛 ID 集合
  const list = ongoing.getList()
  const activeIds = new Set(list.map(v => v.id))
  
  // 2. 遍历 Storage 中所有的 Key
  const keys = wx.getStorageInfoSync().keys
  
  keys.forEach(k => {
    // 3. 识别比赛快照 Key 格式
    if (k.startsWith('zhongba_match_current_')) {
      const id = Number(k.split('_').pop())
      // 4. 如果 ID 不在存活列表中,视为"孤儿数据",直接删除
      if (!activeIds.has(id)) {
        safeRemove(k)
        console.log(`[GC] Cleaned up orphan match: ${id}`)
      }
    }
  })
}

这个机制保证了 Storage 永远只存储有用的数据,既节省空间又维护了整洁。

最后我还让它生成了一份数据快照,以便以后接入服务端的时候可以快速的创建数据库:


三、 细节体验:后台计时校准

小程序在切入后台(onHide)后,setInterval 定时器往往会暂停或变慢。为了保证比赛计时的准确性,不能单纯依赖定时器累加。

解决方案:时间戳校准法

  1. 记录时间点onHide 时,记录当前时间戳 runningSince
  2. 计算差值onShow 时,计算 (Date.now() - runningSince)
  3. 自动补齐 :将差值加到 elapsedTime 中。
javascript 复制代码
// pages/nine-ball/nine-ball.js
onShow() {
  if (this.data.isRunning) {
    const now = Date.now()
    const rs = this.data.runningSince
    const delta = Math.floor((now - rs) / 1000)
    
    // 即使在后台挂起了一小时,回来时间也会瞬间补齐
    if (delta > 0) {
      this.setData({ elapsedTime: this.data.elapsedTime + delta })
    }
  }
}

四、 总结

"追分记"虽然只是一个工具类小程序,但"麻雀虽小,五脏俱全"。

  • 从产品角度:它验证了从痛点出发,利用 AI 辅助设计快速落地的可行性。
  • 从技术角度:本地存储治理、生命周期管理等前端/小程序开发的典型场景。

独立开发最迷人的地方,莫过于看着一个想法,在自己的键盘下一点点变成触手可及的现实。

如果你也是台球爱好者,或者对小程序开发感兴趣,欢迎在微信搜索**"追分记"**体验,也欢迎在评论区交流技术细节!

相关推荐
imkaifan8 小时前
bind函数--修改this指向,返回一个函数
开发语言·前端·javascript·bind函数
乌日尼乐8 小时前
【Java基础整理】Java多线程
java·后端
xkxnq8 小时前
第一阶段:Vue 基础入门(第 7 天)
前端·javascript·vue.js
光头闪亮亮8 小时前
企业协同办公系统(OA)-【图标选择器】模块开发详解
前端·javascript·vue.js
神秘的猪头8 小时前
从“抽卡”到“规范驱动”:Vibe Coding 的进化史与计分小程序实战 🚀
ai编程·trae·vibecoding
pas1368 小时前
22-mini-vue props
前端·javascript·vue.js
pas1368 小时前
23-mini-vue 实现 emit 功能
前端·javascript·vue.js
百度地图汽车版8 小时前
【智图译站】基于 LightGBM 与 GNSS 多特征驱动的 NLOS 误差可靠识别方法
前端
有意义8 小时前
用心写好一个登录页:代码、体验与细节的平衡
前端·react.js·交互设计
程序员Agions8 小时前
React 自定义 Hooks 生存指南:7 个让你少加班的"偷懒"神器
前端·javascript