尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

用Claude和localStorage实现网页断电自救:赛博城市单文件实战

用Claude和localStorage实现网页断电自救:赛博城市单文件实战 Claude 生成一个 HTML 文件不难难的是让这个文件在断电、刷新、误关闭之后还能自己恢复现场。我最近用 Claude 现场搭了一个赛博城市页面Canvas 画霓虹高楼、雨夜街景、飞行车城市名称、地图种子、粒子密度这些参数全部存进浏览器本地。测试时我直接把浏览器强制关掉重新打开那个 HTML 文件页面能恢复到关闭前的城市状态。这个组合听起来很炫但它不是靠什么特殊能力Claude 负责把页面代码生成出来真正扛住“断电”的是前端最基础的 localStorage。这篇文章适合三类人看想用 Claude 生成前端页面但又不想折腾构建工具的前端学习者、喜欢做单文件 H5 小作品的人、以及准备把 AI 生成页面落地成可交互产品但不知道状态怎么保存的开发者。看完你会明白两件事第一怎样把“赛博城市”这种偏展示型的想法拆给 Claude 写第二怎么让一个纯前端页面在本地把现场状态救回来。下面按我实际跑通的顺序拆一遍。1. 先搞清楚“断电自救”救的到底是什么1.1 不是真扛断电而是状态恢复先把这个概念说清楚避免一上来就产生错误期待。网页在运行时城市里的粒子坐标、霓虹灯位置、当前动画帧都存在内存里。断电或者强制关闭浏览器内存直接清空任何网页都救不回来。所谓“断电自救”真正的含义是页面在状态发生变化时提前把关键数据写到浏览器本地存储里下次打开页面时读取这些数据恢复到上一次的样子。这里有个很重要的判断要区分“现场状态”和“再生参数”。粒子每一帧的位置是现场状态断电丢了就算了下次重新推演就行。真正必须保存的是地图种子、城市名称、夜间模式、粒子密度这些再生参数。只要把这些参数保存好重新打开页面时城市就能按照同样的规则重新长出来。很多新手会让 Claude 把所有东西都存下来反而把问题搞复杂。状态设计的原则是只保存“能生成现场的参数”不要保存“现场本身”。1.2 为什么单 HTML 页面适合这个场景赛博城市这种演示型页面最适合做成单 HTML 文件。所谓单 HTML就是所有 CSS、JavaScript 都内联在一个.html文件里不需要构建工具不需要安装依赖也不需要网络请求。Claude 在对话里可以直接输出完整的 index.html。用户把这个文件保存到本地双击用浏览器打开就能看到效果。这对 AI 生成前端页面来说是最省事的交付形式。这种形式的另一个好处是方便传播。发给别人一个文件别人也能直接打开。配合“断电自救”能力一个小文件就变成了一个可以反复打开、状态不丢失的微型应用。1.3 localStorage、IndexedDB、URL 参数怎么选“断电自救”本质上是选一种浏览器本地存储方案。常见选择有四种方案存储位置容量读写方式适合场景localStorage浏览器本地通常约 5MB同步保存 JSON 小状态IndexedDB浏览器本地通常更大异步复杂结构、大文件、图片音频URL 参数地址栏很小同步分享页面快照不适合长期保存后端数据库服务器大异步跨设备同步、账号系统赛博城市的城市状态无非是几个数字、字符串和数组。一次 JSON 序列化下来一般只有几十 KB。用 localStorage 最简单直接同步读写写一个setItem、读一个getItem就够用。用 IndexedDB 也可以但在这个场景里属于过度设计。URL 参数适合做“分享码”把一个城市快照压缩成短字符串放到地址栏里让别人打开后直接看到同一座城市但不能作为持续保存方案。如果要做跨设备同步那就必须引入后端不是纯前端单 HTML 能解决的。2. 用 Claude 生成赛博城市的提示词和套路2.1 先框定交付物再让 AI 动手很多人让 Claude 生成页面只说一句“给我一个赛博城市”。结果 Claude 可能给你一个 React 项目、一份多文件代码或者引了一堆外部 CDN 资源。网络好的时候能跑断网就白屏更别提本地双击打开。所以我每次都会在提示词里先写清楚交付物边界。核心约束是三条单个 HTML 文件、无外部 CDN、无构建工具。后面的视觉和保存逻辑都基于这个前提展开。如果目标是做“断电自救”还要把“自动保存并恢复状态”作为显式需求写进提示词不要指望 AI 自己想到。Claude 很擅长按需求补代码但不加约束时它倾向于生成看起来酷炫但缺少工程细节的页面。2.2 我给 Claude 的提示词模板下面这个提示词可以作为起点如果你要做类似的单 HTML 页面可以直接替换主题请生成一个完整的、可直接运行的 index.html - 赛博朋克风格城市夜景使用 Canvas 绘制 - 包含霓虹灯、高楼、街道、雨滴、飞行车 - 页面下方显示当前时间、天气、城市名称 - 左上角提供控制项城市名称、地图种子、粒子密度、夜间模式 - 把控制项和城市状态用 localStorage 保存页面刷新或重新打开时恢复 - 不要使用外部 CDN、不要构建工具、不要网络请求 - CSS 和 JavaScript 全部写在 HTML 内部这些需求不是随便写的。控制项是为了方便验证“断电自救”。如果页面没有任何可修改的状态你根本没法判断保存有没有生效。有了城市名称、地图种子、粒子密度就能改一个值刷新看它是否保留。“无外部 CDN、无网络请求”保证离线可运行。这一点在验证断电自救时尤其重要因为当页面断网或本地环境不稳定时页面至少不会因为加载不到资源而白屏。2.3 网页版对话还是 Claude Code实际生成方式有两种网页版对话和 Claude Code 命令行模式。网页版适合一次性生成。你把提示词发过去等它输出完整代码复制保存成 index.html。优点是零安装打开浏览器就能用缺点是大段代码复制容易出错尤其是代码特别长的时候。Claude Code 更适合反复迭代。它可以把 HTML 文件直接写到工作目录里你改了需求它直接在文件里改代码。如果你已经配置好了 Claude Code 环境用起来会顺很多。需要说明的是无论用哪种方式前提都是官方 Claude 服务在你的环境里可以正常使用。网站端和命令行工具只是入口不同生成能力没有本质区别。2.4 防止输出被截断或格式错乱AI 在一次输出里生成几百行甚至上千行 HTML 时经常会被截断。文件保存之后浏览器打开可能白屏或者报错原因往往是结尾的/html标签没出现。我的做法是分步生成。先让 Claude 生成页面骨架HTML 结构、控制项、状态保存和加载逻辑。确认这个骨架能跑通后再让它补充 Canvas 绘制赛博城市的具体函数。这样每次输出量小一点完整度更高。保存文件时要特别检查文件尾部。一个完整的 HTML 文件应该以/html结尾。如果只复制了对话输出的一部分后面标签没闭合页面运行就会不稳定。另外浏览器地址栏里用data:text/html形式快速预览一小段代码是可以的但它不适合作为正式保存方式。别拿它当代替文件保存的方案刷新后如果参数丢失第一反应应该是 localStorage 或文件协议问题而不是工具问题。3. 断电自救的核心实现保存、恢复、兜底3.1 先设计状态字段在让 Claude 写保存逻辑之前最好先把状态字段定下来。我用的城市状态大致长这样{ version: 1, cityName: Neon Harbor, mapSeed: 20250214, nightMode: true, particleDensity: 60, unlockedBuildings: [central-tower, east-market], savedAt: 1740000000000 }字段含义如下version状态版本号用于后续迁移和兼容。cityName城市名称页面标题、角落展示都会用它。mapSeed地图种子根据同一个种子生成同样的城市布局。nightMode夜间模式开关决定霓虹配色和背景亮度。particleDensity雨滴和霓虹粒子密度影响画面复杂度。unlockedBuildings用户通过交互解锁的建筑集合是一个数组。savedAt保存时间戳方便调试时看数据有没有更新。把mapSeed单独拿出来很重要。城市里的楼、街道、招牌位置都可以用随机数生成。只要随机数种子一样生成结果就能复现。这样即使粒子位置全丢了下一次打开页面城市还是同一座。3.2 保存时机不要在每帧动画里写 localStorage这是整个“断电自救”最容易踩坑的地方。动画页面的主循环通常是requestAnimationFrame每帧都会执行。如果在这一帧里调localStorage.setItem页面会明显变得卡顿严重时甚至直接卡死。因为localStorage是同步操作频繁写入会阻塞主线程。正确的保存时机有三个用户修改控制项后立刻保存。页面关闭前通过beforeunload事件尝试保存。设置一个定时器比如每 30 秒自动保存一次作为兜底。保存的内容始终是“再生参数”不是画面里每一粒雨滴的坐标。雨滴坐标每帧重新计算就行不需要存档。3.3 读取与兜底版本号、try/catch、损坏数据清理恢复逻辑比保存逻辑更需要谨慎。因为本地存储里的数据可能损坏可能来自旧版本也可能被用户手动改过。读取流程我建议这样设计从 localStorage 里取原始字符串。如果取不到直接返回默认状态。如果能取到用JSON.parse转成对象。如果解析失败、对象为空、version不匹配就丢弃它返回默认状态。如果解析成功用默认状态做底并把读到的字段覆盖进去。最后一步很重要。这样即使以后状态里新增了字段老数据读进来也不会缺字段。3.4 一个直接能用的 localStorage 封装下面这段代码可以作为需求片段也可以直接粘进 HTML 的script标签里。它做的事情就是保存、读取、兜底三层。const CITY_STATE_KEY cyber-city-v1; function defaultState() { return { version: 1, cityName: Neon Harbor, mapSeed: 20250214, nightMode: true, particleDensity: 60, unlockedBuildings: [], savedAt: 0, }; } function saveCityState(state) { try { const data JSON.stringify({ ...state, savedAt: Date.now() }); localStorage.setItem(CITY_STATE_KEY, data); return true; } catch (e) { console.warn([city] save failed, e); return false; } } function loadCityState() { try { const raw localStorage.getItem(CITY_STATE_KEY); if (!raw) return defaultState(); const data JSON.parse(raw); if (!data || data.version ! 1) { localStorage.removeItem(CITY_STATE_KEY); return defaultState(); } return { ...defaultState(), ...data }; } catch (e) { console.warn([city] load failed, reset, e); localStorage.removeItem(CITY_STATE_KEY); return defaultState(); } }封装的好处是保存失败不会让页面报错读取失败不会让页面白屏数据格式不对会自动清理。这正是“断电自救”最核心的兜底逻辑。3.5 怎么让 Claude 把这段逻辑整合进城市页面如果你不是手写整个页面而是让 Claude 生成可以在后续提示词里这样要求“页面加载时调用loadCityState初始化城市状态用户修改控制项时调用saveCityState保存状态Canvas 绘制函数根据state.mapSeed生成城市布局。”这三句话会把保存逻辑和绘制逻辑串起来。Claude 不需要重新发明状态管理只需要按照这个接口把代码接上。即使你换一个会话重新生成只要保留这个接口约定代码也能复用。4. 现场运行从单文件到真实环境验证4.1 环境只需要浏览器和文本编辑器这个方案对环境要求极低。一个现代浏览器加一个文本编辑器就够。保存 HTML 文件时注意用 UTF-8 编码避免中文标题和城市名乱码。打开方式有两个选择直接双击 HTML 文件用默认浏览器打开。拖拽 HTML 文件到浏览器窗口里打开。大多数情况下直接双击就能跑。如果页面上有fetch请求或者你想完全模拟真实 Web 环境可以起一个本地静态服务。在文件所在目录执行类似python -m http.server 8080的命令然后访问http://localhost:8080就行。VS Code 的 Live Server 插件也是同样思路。为什么推荐起本地服务因为不同浏览器对file://协议下 localStorage 的处理策略不完全一致。直接双击文件在多数环境里没问题但偶尔会遇到状态不持久的情况。换成 HTTP 方式打开后存储行为往往就正常了。4.2 按这个顺序验证“断电自救”不管页面是 Claude 生成的还是手写的验证顺序建议固定下来第一次打开确认页面生成了一座随机赛博城市。修改一个控制项比如把城市名称改成 “Neon Harbor”把粒子密度调高。刷新页面确认城市名称和粒子密度仍然保留。强制关闭浏览器标签页再重新打开同一个 HTML 文件确认状态还在。清空 localStorage刷新页面确认页面能回退到默认状态而不是白屏。断开网络再打开页面确认城市仍然能渲染因为没有外部依赖。我一般不用“刷新”作为唯一验证标准。强制关闭浏览器再打开才更接近“断电”场景。4.3 判断标准哪些现象算通过很多同学不知道到什么程度算成功。这里列几个明确标准页面加载后不白屏控制台没有红色报错。刷新后控制项里的值保持上一次修改后的结果。城市布局没有乱掉地图种子没变。关闭浏览器再打开状态还在。存储体积很小在开发者工具的 Application 面板里能看到cyber-city-v1这个 key内容是一个 JSON 字符串。如果这些条件都满足断电自救基本就成立了。4.4 Claude Code 场景下的常见报错排查如果你选择用 Claude Code 来生成和修改文件安装环境时可能会遇到一个常见报错error: claude native binary not installed. either postinstall did not run...这个报错的意思是安装过程中某个后置脚本没有执行。常见原因有三个Node.js 或包管理器版本不兼容、安装过程中网络异常导致脚本中断、包管理器缓存损坏。排查顺序建议从环境开始确认 Node.js 版本是否满足工具要求。确认包管理器状态是否正常。卸载后重新安装让后置脚本重新执行。如果仍然报错查看官方文档或安装日志不要手动跳过安装脚本。这里想提醒一句不要看到报错就去改安装脚本跳过 postinstall那不是解决问题的方向。正确的做法是找到为什么脚本没有执行然后恢复正常安装流程。5. 资源占用、边界和更实用的扩展方向5.1 单文件动画页的资源边界赛博城市页面看起来炫但资源占用很容易失控。Canvas 里粒子数量、霓虹灯数量、绘制函数复杂度都会直接影响帧率。我在测试时把particleDensity从 60 直接调到 120帧率肉眼可见地下降CPU 占用明显升高。如果你的机器配置不高建议默认值控制在 40 到 60 之间并且让这个参数在控制项里可调而不是写死在代码里。还要注意 DOM 节点数量。有的 AI 生成代码会不断创建新节点比如每帧都往页面里塞一个霓虹文字标签跑几分钟后 DOM 越来越重。正确的做法是复用已有节点或者直接在 Canvas 里绘制文字和图形。5.2 把单个页面扩展成可配置的赛博城市生成器这个项目天然可以扩展成一个小型生成器。状态里已经有mapSeed可以继续加天气系统、日夜循环、随机事件、建筑解锁、成就列表。每加一类功能就对应扩展状态对象里的几个字段。比如加一个“日夜循环”状态里加dayCycle和cycleSpeed页面根据时间切换配色。加“建筑解锁”点击特定建筑后把建筑 id 放到unlockedBuildings数组里并保存。下次重新打开已经解锁的建筑保持解锁状态。如果担心状态字段越来越多可以给version字段升级。比如从 1 升级到 2然后在加载逻辑里做版本迁移读到 version 1 的数据补上新增字段后保存成 version 2。这个做法在本地单文件应用里已经够用。5.3 这个方案不适合什么场景要诚实地说localStorage 保存状态不是万能的。它只适合单机、单人、轻量状态。如果城市数据需要跨设备同步没有戏。localStorage 存在当前浏览器的当前站点下换一台设备不会跟着走。如果用户清除浏览器站点数据状态也会丢失。如果数据重要到不能丢必须上后端数据库或者至少用 IndexedDB 加云端备份。多用户协作也不用考虑这个方案。两个人在同一台设备上打开同一个 HTML会读写同一个 localStorage key。要做区分需要引入用户 ID 或者独立的存储分区。明确了边界你就不会在后面的项目里拿 localStorage 硬扛不该它扛的场景。6. 常见问题排查清单6.1 白屏或页面无法打开先看控制台有没有报错。F12 打开开发者工具切到 Console红色报错信息就是第一线索。然后检查文件完整度。如果一个 HTML 文件没有保存完整经常是缺少后半段代码导致/html不存在。Claude 生成超长代码时这种问题很常见。最后检查网络请求。如果在提示词里没有约束“无外部 CDN”页面可能去加载线上资源断网之后白屏。这个问题的解决方式是修改页面去掉外部依赖全部内联。6.2 状态恢复失败状态不恢复先按这个顺序排查localStorage 的 key 是否一致。保存和读取必须用同一个 key。是否使用了隐私模式或无痕模式部分浏览器在这种模式下不持久化数据。页面是通过file://打开还是 HTTP 打开遇到异常先换成静态服务试试。读取时是否被try/catch吞掉了异常。打开控制台看[city] load failed这样的调试日志。本地存储里是不是已经有旧数据旧数据的 version 和当前代码不匹配被兜底逻辑清掉了。这些原因里最常见的是 key 不一致和 file 协议存储策略差异。6.3 Claude 输出截断或格式错乱如果你发现 Claude 生成的代码总是不完整调整策略而不是一直重发。把提示词拆小先让它生成骨架再分模块生成城市绘制逻辑。保存文件后用浏览器打开。如果报错指向某个函数不存在去检查那个函数是不是在截断时被切掉了。再次让 Claude 补充时直接把当前报错信息贴给它它通常能定位到问题。6.4 页面卡顿页面卡顿先看资源占用。把粒子密度调低观察是否恢复。如果恢复说明当前绘制量超过机器承受范围。同时检查有没有在动画帧里写 localStorage、创建大量 DOM 节点、或者监听 resize 事件后反复执行复杂计算。这些都是前端动画页面常见的性能杀手。6.5 本地存储失效有些用户在浏览器设置里禁用了站点数据、Cookie 或者存储。这种情况下 localStorage 会失效页面表现为状态永远保留不住。这种属于浏览器的正常安全策略不是代码 bug。处理方式有两种要么引导用户允许站点存储数据要么在页面里给出提示告诉用户当前环境无法保存状态。对单 HTML 演示页来说能跑、能恢复就已经完成了任务。这次实测里最值得记住的一条经验是让 Claude 生成页面不能只提视觉效果还要把状态边界说清楚。视觉效果是一眼能看到的“断电自救”这种能力才是用户真正会觉得“这页面有脑子”的地方。我自己的做法是先把保存、恢复、兜底这条链路跑通再去堆霓虹灯和粒子数量。步骤顺序反了后面改起来会很痛苦。
返回列表