目录:
在 AI 辅助编程的时代,我们如何利用 Claude Code 这样的智能工具来构建一个完整的 Web 应用?本文将详细记录使用 Claude Code 开发一个功能完整的离线记事本 PWA (Progressive Web App) 的全过程,展示 AI 编程助手如何帮助我们快速实现从需求到部署的完整开发流程。
这个项目的特别之处在于:它是一个零依赖框架的纯 JavaScript 应用,支持 Markdown 渲染和 JSON 可视化,并且可以完全离线工作。更重要的是,整个开发过程展示了如何与 AI 编程助手高效协作。
项目概览
我们要构建的是一个具有以下特性的离线记事本应用:
- ✅ 完全离线支持 - 使用 Service Worker 实现离线缓存
- ✅ PWA 可安装 - 可以像原生应用一样安装到桌面
- ✅ Markdown 支持 - 实时预览 Markdown 渲染效果
- ✅ JSON 可视化 - 智能识别 JSON 内容并提供可折叠的语法高亮显示
- ✅ 实时搜索 - 按标题和内容过滤笔记
- ✅ 响应式设计 - 适配移动端和桌面端
- ✅ 零框架依赖 - 纯 vanilla JavaScript (除了 Markdown 解析库)
技术栈:
- HTML5 + CSS3
- Vanilla JavaScript (ES6+)
- LocalStorage API (数据持久化)
- Service Worker API (离线支持)
- Web App Manifest (PWA 配置)
- Marked.js (Markdown 解析)
第一步:与 Claude Code 明确需求
在开始编码之前,与 Claude Code 的第一次对话至关重要。清晰的需求描述能让 AI 更好地理解项目目标。
我的初始提示词:
我想创建一个离线记事本 PWA 应用,需要具备以下功能:
1. 创建、编辑、删除笔记
2. 支持 Markdown 格式
3. 能够离线使用
4. 可以安装到桌面
5. 数据保存在浏览器本地
6. 实时搜索功能
7. 能够识别和美化 JSON 内容
技术要求:
- 不使用任何前端框架,用纯 JavaScript 实现
- 响应式设计,支持移动端
- 使用 Service Worker 实现离线功能
Claude Code 的响应策略:
Claude Code 首先会询问一些关键的设计决策:
- 数据存储方式 (LocalStorage vs IndexedDB)
- UI 风格偏好 (简约现代 vs 经典样式)
- Markdown 库选择 (Marked.js vs Markdown-it)
- 是否需要数据导出功能
这个交互过程帮助我们明确了技术选型和设计方向。
第二步:项目结构设计
基于需求分析,Claude Code 建议了一个简洁的项目结构:
notepad/
├── index.html # 主页面结构
├── styles.css # 样式表 (538 行)
├── app.js # 核心应用逻辑 (398 行)
├── sw.js # Service Worker (71 行)
├── manifest.json # PWA 配置文件
└── README.md # 项目文档
设计原则:
- 关注点分离 - HTML (结构)、CSS (样式)、JS (逻辑) 独立
- 单一职责 - 每个文件有明确的功能边界
- 最小化依赖 - 只引入必要的外部库 (Marked.js)
第三步:构建核心数据模型
3.1 数据结构设计
我向 Claude Code 描述了笔记的基本属性需求,它建议了以下数据模型:
// 笔记数据结构
{
id: "1675332000000", // 时间戳作为唯一 ID
title: "我的第一条笔记",
content: "支持 **Markdown** 和 JSON",
createdAt: "2025-02-02T10:00:00.000Z",
updatedAt: "2025-02-02T10:30:00.000Z"
}
// generated by hugo's coding agent
设计亮点:
- 使用时间戳生成唯一 ID,避免 UUID 库依赖
- ISO 8601 格式的时间戳便于国际化
- 简单的扁平结构,易于序列化到 LocalStorage
3.2 应用核心类
Claude Code 建议使用 ES6 类来组织应用逻辑:
class NotesApp {
constructor() {
this.notes = []; // 笔记数组
this.currentNoteId = null; // 当前编辑的笔记 ID
this.isPreviewMode = false; // 预览模式标志
}
// 初始化应用
init() {
this.loadNotes();
this.bindEvents();
this.registerServiceWorker();
this.showList();
}
// 从 LocalStorage 加载笔记
loadNotes() {
const stored = localStorage.getItem('notes');
this.notes = stored ? JSON.parse(stored) : [];
}
// 保存笔记到 LocalStorage
saveNotes() {
localStorage.setItem('notes', JSON.stringify(this.notes));
}
// 绑定所有事件监听器
bindEvents() {
// 新建笔记按钮
document.getElementById('newNoteBtn')
.addEventListener('click', () => this.showEditor(null));
// 返回列表按钮
document.getElementById('backBtn')
.addEventListener('click', () => this.showList());
// 保存按钮
document.getElementById('saveBtn')
.addEventListener('click', () => this.saveNote());
// 删除按钮
document.getElementById('deleteBtn')
.addEventListener('click', () => this.deleteNote());
// 搜索输入框
document.getElementById('searchInput')
.addEventListener('input', (e) => this.searchNotes(e.target.value));
// 预览切换按钮
document.getElementById('previewBtn')
.addEventListener('click', () => this.togglePreview());
// 实时预览更新
document.getElementById('noteContent')
.addEventListener('input', () => this.updatePreview());
}
// 显示笔记列表视图
showList() {
document.getElementById('listView').style.display = 'block';
document.getElementById('editView').style.display = 'none';
this.renderNotesList(this.notes);
}
// 显示编辑器视图
showEditor(noteId) {
this.currentNoteId = noteId;
const note = noteId ? this.notes.find(n => n.id === noteId) : null;
document.getElementById('noteTitle').value = note ? note.title : '';
document.getElementById('noteContent').value = note ? note.content : '';
document.getElementById('listView').style.display = 'none';
document.getElementById('editView').style.display = 'block';
// 新建笔记时自动聚焦标题
if (!noteId) {
document.getElementById('noteTitle').focus();
}
this.updatePreview();
this.updateJsonIndicator();
}
// CRUD 操作省略...
}
// 初始化应用
const app = new NotesApp();
app.init();
// generated by hugo's coding agent
与 Claude Code 的协作要点:
- 迭代式开发 - 先实现基础的 CRUD 功能,再添加高级特性
- 代码审查 - 每次生成代码后,我会要求 Claude Code 检查潜在的 bug 和性能问题
- XSS 防护 - Claude Code 主动建议添加 HTML 转义函数防止 XSS 攻击
// Claude Code 建议的 XSS 防护函数
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// generated by hugo's coding agent
第四步:实现 Markdown 支持
4.1 集成 Marked.js
我向 Claude Code 询问:“如何添加 Markdown 预览功能?”
它建议使用轻量级的 Marked.js 库,并提供了实现代码:
// 渲染 Markdown 预览
renderMarkdownPreview() {
const content = document.getElementById('noteContent').value;
const previewContainer = document.getElementById('markdownPreview');
// 检测是否为 JSON 格式
if (this.isValidJson(content)) {
this.renderJsonPreview(content, previewContainer);
} else {
// 使用 Marked.js 渲染 Markdown
previewContainer.innerHTML = marked.parse(content);
previewContainer.className = 'markdown-preview';
}
}
// 验证 JSON 格式
isValidJson(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
// generated by hugo's coding agent
4.2 Markdown 样式优化
Claude Code 还生成了完整的 Markdown 样式表:
/* Markdown 渲染样式 */
.markdown-preview {
padding: 20px;
background: white;
border-radius: 8px;
line-height: 1.8;
}
.markdown-preview h1 {
font-size: 2em;
border-bottom: 2px solid #667eea;
padding-bottom: 10px;
margin-bottom: 20px;
}
.markdown-preview h2 {
font-size: 1.5em;
color: #667eea;
margin-top: 30px;
}
.markdown-preview code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
}
.markdown-preview pre {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 6px;
overflow-x: auto;
}
.markdown-preview blockquote {
border-left: 4px solid #667eea;
padding-left: 20px;
color: #666;
margin: 20px 0;
font-style: italic;
}
/* generated by hugo's coding agent */
第五步:创新的 JSON 可视化功能
这是整个项目最有趣的部分。当我向 Claude Code 提出:“能否自动识别 JSON 内容并提供更好的显示效果?“它提出了一个完整的 JSON 可视化方案。
5.1 JSON 检测和徽章显示
// 更新 JSON 指示器
updateJsonIndicator() {
const content = document.getElementById('noteContent').value;
const indicator = document.getElementById('jsonIndicator');
if (this.isValidJson(content)) {
indicator.textContent = '📋 JSON';
indicator.style.display = 'inline-block';
} else {
indicator.style.display = 'none';
}
}
// generated by hugo's coding agent
5.2 JSON 语法高亮渲染器
Claude Code 生成了一个复杂但高效的 JSON 渲染函数:
renderJsonPreview(jsonString, container) {
try {
const data = JSON.parse(jsonString);
container.className = 'json-viewer';
container.innerHTML = this.renderJsonNode(data, 0);
this.bindJsonToggleEvents();
} catch (e) {
container.innerHTML = `
<div class="json-error">
<strong>JSON 解析错误:</strong>
<pre>${this.escapeHtml(e.message)}</pre>
</div>
`;
}
}
// 递归渲染 JSON 节点
renderJsonNode(data, level) {
const indent = ' '.repeat(level);
if (data === null) return '<span class="json-null">null</span>';
if (data === undefined) return '<span class="json-undefined">undefined</span>';
const type = typeof data;
// 布尔值
if (type === 'boolean') {
return `<span class="json-boolean">${data}</span>`;
}
// 数字
if (type === 'number') {
return `<span class="json-number">${data}</span>`;
}
// 字符串
if (type === 'string') {
// 检测 URL
const urlRegex = /^https?:\/\/.+/;
if (urlRegex.test(data)) {
return `<a href="${data}" target="_blank" class="json-url">"${this.escapeHtml(data)}"</a>`;
}
// 长文本处理
if (data.length > 100) {
const preview = this.escapeHtml(data.substring(0, 100));
const full = this.escapeHtml(data);
return `
<span class="json-string-long">
"<span class="json-string-preview">${preview}...</span>
<span class="json-string-full" style="display:none;">${full}</span>
<button class="json-expand-btn">Show More</button>"
</span>
`;
}
return `<span class="json-string">"${this.escapeHtml(data)}"</span>`;
}
// 数组
if (Array.isArray(data)) {
if (data.length === 0) return '[]';
const items = data.map((item, index) => {
return `${indent} ${this.renderJsonNode(item, level + 1)}${index < data.length - 1 ? ',' : ''}`;
}).join('\n');
return `
<span class="json-bracket">[</span>
<span class="json-array-count">${data.length} items</span>
<button class="json-toggle" data-collapsed="false">−</button>
<div class="json-content">
\n${items}\n${indent}
</div>
<span class="json-bracket">]</span>
`;
}
// 对象
if (type === 'object') {
const keys = Object.keys(data);
if (keys.length === 0) return '{}';
const properties = keys.map((key, index) => {
const value = this.renderJsonNode(data[key], level + 1);
return `${indent} <span class="json-key">"${this.escapeHtml(key)}"</span>: ${value}${index < keys.length - 1 ? ',' : ''}`;
}).join('\n');
return `
<span class="json-bracket">{</span>
<span class="json-object-count">${keys.length} fields</span>
<button class="json-toggle" data-collapsed="false">−</button>
<div class="json-content">
\n${properties}\n${indent}
</div>
<span class="json-bracket">}</span>
`;
}
return String(data);
}
// generated by hugo's coding agent
5.3 JSON 折叠/展开交互
// 绑定 JSON 折叠按钮事件
bindJsonToggleEvents() {
document.querySelectorAll('.json-toggle').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const isCollapsed = btn.dataset.collapsed === 'true';
const content = btn.nextElementSibling;
if (isCollapsed) {
content.style.display = 'block';
btn.textContent = '−';
btn.dataset.collapsed = 'false';
} else {
content.style.display = 'none';
btn.textContent = '+';
btn.dataset.collapsed = 'true';
}
});
});
// 长文本展开按钮
document.querySelectorAll('.json-expand-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const container = btn.closest('.json-string-long');
const preview = container.querySelector('.json-string-preview');
const full = container.querySelector('.json-string-full');
if (full.style.display === 'none') {
preview.style.display = 'none';
full.style.display = 'inline';
btn.textContent = 'Show Less';
} else {
preview.style.display = 'inline';
full.style.display = 'none';
btn.textContent = 'Show More';
}
});
});
}
// generated by hugo's coding agent
JSON 可视化效果展示:
{
"user": {
"id": 12345,
"name": "张三",
"email": "zhangsan@example.com",
"isActive": true,
"profile": {
"bio": "这是一段很长的个人简介...",
"website": "https://example.com",
"tags": ["developer", "blogger", "AI enthusiast"]
}
}
}
渲染后会显示:
- 语法高亮 (键、值、括号不同颜色)
- 可折叠的对象和数组
- 字段/项目计数
- 长文本自动截断并提供展开按钮
- URL 自动转为可点击链接
第六步:实现 PWA 离线功能
6.1 Service Worker 缓存策略
我向 Claude Code 询问:“如何实现离线支持?“它解释了 Service Worker 的工作原理,并生成了完整的实现:
// sw.js - Service Worker
const CACHE_NAME = 'notepad-v1';
const URLS_TO_CACHE = [
'/',
'/index.html',
'/styles.css',
'/app.js',
'/manifest.json',
'https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js'
];
// 安装事件 - 缓存核心资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('缓存已打开');
return cache.addAll(URLS_TO_CACHE);
})
);
});
// 激活事件 - 清理旧缓存
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
console.log('删除旧缓存:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
// 拦截请求 - Cache First 策略
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 缓存命中,返回缓存
if (response) {
return response;
}
// 缓存未命中,发起网络请求
return fetch(event.request).then(response => {
// 检查是否为有效响应
if (!response || response.status !== 200 || response.type === 'error') {
return response;
}
// 克隆响应并缓存
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
// generated by hugo's coding agent
缓存策略说明:
Claude Code 向我解释了三种常见的 Service Worker 缓存策略:
- Cache First (本项目采用) - 优先使用缓存,适合静态资源
- Network First - 优先网络,适合动态内容
- Stale While Revalidate - 返回缓存的同时更新缓存,平衡速度和新鲜度
对于离线记事本应用,Cache First 是最佳选择,因为:
- 应用资源不经常变化
- 用户数据存储在 LocalStorage,不依赖网络
- 优先保证应用可用性
6.2 注册 Service Worker
// 在 NotesApp 类中注册
registerServiceWorker() {
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker 注册成功:', registration.scope);
})
.catch(error => {
console.log('Service Worker 注册失败:', error);
});
});
}
}
// generated by hugo's coding agent
6.3 Web App Manifest 配置
{
"name": "离线记事本",
"short_name": "记事本",
"description": "功能完整的离线记事本应用",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#667eea",
"orientation": "portrait-primary",
"icons": [
{
"src": "icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Manifest 配置要点:
display: "standalone"- 隐藏浏览器 UI,像原生应用一样显示theme_color- 匹配应用主色调 (#667eea 紫色)- 图标尺寸遵循 PWA 标准 (192x192 和 512x512)
第七步:UI/UX 设计与实现
7.1 设计系统
我向 Claude Code 描述了设计需求:“现代简约风格,紫色渐变主题,卡片式布局。”
它生成了完整的设计系统:
:root {
/* 颜色变量 */
--primary-color: #667eea;
--secondary-color: #764ba2;
--text-dark: #333;
--text-light: #666;
--bg-light: #f5f5f5;
--border-color: #ddd;
--shadow: 0 2px 8px rgba(0,0,0,0.1);
--shadow-hover: 0 4px 12px rgba(0,0,0,0.15);
}
/* 渐变背景头部 */
header {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
color: white;
padding: 20px;
box-shadow: var(--shadow);
}
/* 卡片式笔记布局 */
.note-card {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 15px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: var(--shadow);
}
.note-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-hover);
}
/* 响应式网格布局 */
.notes-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
/* 移动端适配 */
@media (max-width: 768px) {
.notes-grid {
grid-template-columns: 1fr;
}
.toolbar {
flex-direction: column;
gap: 10px;
}
button {
width: 100%;
}
}
/* generated by hugo's coding agent */
7.2 交互反馈
Claude Code 还建议添加微交互增强用户体验:
/* 按钮悬停效果 */
button {
transition: all 0.2s ease;
}
button:hover {
transform: scale(1.05);
box-shadow: var(--shadow-hover);
}
button:active {
transform: scale(0.98);
}
/* 输入框焦点状态 */
input:focus,
textarea:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
/* 平滑过渡动画 */
.view {
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* generated by hugo's coding agent */
第八步:搜索功能实现
8.1 实时搜索过滤
searchNotes(query) {
const searchTerm = query.toLowerCase().trim();
if (!searchTerm) {
// 搜索框为空,显示所有笔记
this.renderNotesList(this.notes);
return;
}
// 过滤笔记:标题或内容包含搜索词
const filtered = this.notes.filter(note => {
const titleMatch = note.title.toLowerCase().includes(searchTerm);
const contentMatch = note.content.toLowerCase().includes(searchTerm);
return titleMatch || contentMatch;
});
this.renderNotesList(filtered);
// 显示搜索结果统计
const resultCount = filtered.length;
const totalCount = this.notes.length;
console.log(`搜索结果: ${resultCount}/${totalCount}`);
}
// generated by hugo's coding agent
8.2 搜索高亮显示 (可选增强)
当我询问 Claude Code:“如何高亮显示搜索结果?“它提供了一个高亮函数:
highlightSearchTerm(text, term) {
if (!term) return this.escapeHtml(text);
const regex = new RegExp(`(${term})`, 'gi');
return this.escapeHtml(text).replace(regex, '<mark>$1</mark>');
}
// 在渲染笔记列表时应用
renderNotesList(notes) {
const searchTerm = document.getElementById('searchInput').value;
const html = notes.map(note => {
const highlightedTitle = this.highlightSearchTerm(note.title, searchTerm);
const preview = note.content.substring(0, 100);
const highlightedPreview = this.highlightSearchTerm(preview, searchTerm);
return `
<div class="note-card" data-id="${note.id}">
<h3>${highlightedTitle}</h3>
<p class="note-preview">${highlightedPreview}...</p>
<div class="note-meta">
<span>${new Date(note.updatedAt).toLocaleString()}</span>
</div>
</div>
`;
}).join('');
document.getElementById('notesList').innerHTML = html || '<p class="empty-state">没有找到匹配的笔记</p>';
}
// generated by hugo's coding agent
第九步:测试与调试
9.1 功能测试清单
在 Claude Code 的帮助下,我创建了完整的测试清单:
基础功能测试:
- ✅ 创建新笔记
- ✅ 编辑现有笔记
- ✅ 删除笔记 (带确认对话框)
- ✅ 搜索笔记
- ✅ 数据持久化 (刷新页面后数据仍存在)
Markdown 测试:
- ✅ 标题渲染 (H1-H6)
- ✅ 粗体和斜体
- ✅ 代码块语法高亮
- ✅ 引用块样式
- ✅ 列表 (有序和无序)
- ✅ 链接和图片
JSON 可视化测试:
- ✅ 简单 JSON 对象
- ✅ 嵌套对象和数组
- ✅ 特殊值 (null, boolean, number)
- ✅ 长文本截断
- ✅ URL 自动链接
- ✅ 折叠/展开交互
- ✅ 无效 JSON 错误提示
PWA 功能测试:
- ✅ Service Worker 注册成功
- ✅ 离线访问 (断网后仍可使用)
- ✅ 应用安装提示
- ✅ 独立窗口显示 (安装后)
响应式测试:
- ✅ 桌面端 (1920x1080)
- ✅ 平板端 (768x1024)
- ✅ 手机端 (375x667)
9.2 Claude Code 辅助调试
Bug 案例 1: JSON 预览闪烁问题
当我报告"输入时 JSON 预览频繁闪烁"的问题后,Claude Code 立即识别出问题并提供解决方案:
// 问题代码 - 每次输入都重新渲染
document.getElementById('noteContent')
.addEventListener('input', () => this.updatePreview());
// 优化方案 - 使用防抖
let previewTimeout;
document.getElementById('noteContent')
.addEventListener('input', () => {
clearTimeout(previewTimeout);
previewTimeout = setTimeout(() => this.updatePreview(), 300);
});
// generated by hugo's coding agent
Bug 案例 2: LocalStorage 溢出
Claude Code 主动提醒我 LocalStorage 的 5MB 限制,并建议添加错误处理:
saveNotes() {
try {
const data = JSON.stringify(this.notes);
localStorage.setItem('notes', data);
} catch (e) {
if (e.name === 'QuotaExceededError') {
alert('存储空间已满!请删除一些笔记。');
console.error('LocalStorage 配额超出:', e);
} else {
alert('保存失败,请重试。');
console.error('保存错误:', e);
}
}
}
// generated by hugo's coding agent
第十步:性能优化
10.1 渲染优化
Claude Code 建议使用批量 DOM 操作减少重绘:
// 优化前 - 逐个插入 DOM
notes.forEach(note => {
const card = createNoteCard(note);
container.appendChild(card);
});
// 优化后 - 一次性更新 innerHTML
renderNotesList(notes) {
const html = notes.map(note => this.createNoteCardHTML(note)).join('');
document.getElementById('notesList').innerHTML = html;
// 重新绑定点击事件
document.querySelectorAll('.note-card').forEach(card => {
card.addEventListener('click', () => {
this.showEditor(card.dataset.id);
});
});
}
// generated by hugo's coding agent
10.2 Service Worker 缓存优化
// 动态缓存策略 - 只缓存 GET 请求
self.addEventListener('fetch', event => {
// 跳过非 GET 请求
if (event.request.method !== 'GET') return;
// 跳过 chrome-extension 等特殊协议
if (!event.request.url.startsWith('http')) return;
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
// generated by hugo's coding agent
关键收获:与 Claude Code 协作的最佳实践
通过这个项目,我总结了以下与 AI 编程助手高效协作的经验:
1. 清晰的需求描述
❌ 模糊: “做一个记事本应用” ✅ 明确: “创建一个支持 Markdown 和 JSON 可视化的 PWA 离线记事本,使用纯 JavaScript,数据存储在 LocalStorage”
2. 迭代式开发
不要试图一次性获得完整代码,而是:
- 先搭建基础框架
- 实现核心 CRUD 功能
- 添加 Markdown 支持
- 实现 JSON 可视化
- 添加 PWA 离线功能
- 优化 UI/UX
- 性能优化和 bug 修复
每个阶段都可以向 Claude Code 请求代码审查和改进建议。
3. 主动询问最佳实践
- “这段代码有性能问题吗?”
- “如何防止 XSS 攻击?”
- “有没有更好的缓存策略?”
- “如何处理 LocalStorage 溢出?”
Claude Code 会主动分析代码并提供专业建议。
4. 利用 AI 的知识广度
当遇到不熟悉的技术时:
- “Service Worker 的三种缓存策略分别适用于什么场景?”
- “PWA Manifest 的必填字段有哪些?”
- “Marked.js 如何配置代码高亮?”
Claude Code 可以快速提供准确的技术信息,省去查文档的时间。
5. 代码审查和重构建议
定期请求 Claude Code 审查代码:
- “这个函数是否符合单一职责原则?”
- “有没有潜在的内存泄漏?”
- “如何重构这段重复代码?”
6. 测试用例生成
询问 Claude Code:“为这个应用生成完整的测试清单”,它会帮你考虑各种边界情况。
7. 文档编写
让 Claude Code 帮助编写:
- 代码注释
- API 文档
- README 文件
- 用户手册
项目成果
最终,我们用不到 1000 行代码 (HTML + CSS + JavaScript) 实现了一个功能完整的 PWA 应用:
代码统计:
index.html: 57 行styles.css: 538 行app.js: 398 行sw.js: 71 行- 总计: 1,064 行
开发时间:
- 传统开发估计: 2-3 天
- 使用 Claude Code: 约 4-6 小时
功能清单:
- ✅ 完整的 CRUD 操作
- ✅ Markdown 实时预览
- ✅ JSON 智能可视化
- ✅ 实时搜索过滤
- ✅ PWA 离线支持
- ✅ 响应式设计
- ✅ XSS 防护
- ✅ 性能优化
部署指南
本地开发
# 克隆项目
git clone https://github.com/yourusername/notepad.git
cd notepad
# 启动本地服务器 (需要 HTTPS 或 localhost 以使用 Service Worker)
python -m http.server 8000
# 或者使用 Node.js
npx http-server -p 8000
# 访问 http://localhost:8000
生产部署
部署到 GitHub Pages:
# 1. 创建 GitHub 仓库
# 2. 推送代码
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/notepad.git
git push -u origin main
# 3. 启用 GitHub Pages (Settings → Pages)
# 4. 访问 https://yourusername.github.io/notepad
部署到 Vercel:
# 安装 Vercel CLI
npm i -g vercel
# 部署
vercel
# 生产部署
vercel --prod
部署到 Netlify:
# 拖拽项目文件夹到 Netlify Drop 即可
# 或使用 CLI
netlify deploy --prod
未来改进方向
与 Claude Code 讨论后,我们列出了一些可能的增强功能:
短期改进
- 数据导出/导入 - 支持 JSON 格式导出和导入
- 标签系统 - 为笔记添加标签分类
- 主题切换 - 支持亮色/暗色主题
- 快捷键支持 - Ctrl+S 保存,Ctrl+N 新建等
中期改进
- 云端同步 - 使用 Firebase 或 Supabase 实现多设备同步
- 协作功能 - 支持多人编辑和评论
- 富文本编辑器 - 集成 WYSIWYG 编辑器
- 附件支持 - 允许上传图片和文件
长期愿景
- AI 辅助写作 - 集成 AI 提供写作建议
- 语音输入 - 支持语音转文字
- OCR 功能 - 图片文字识别
- 智能分类 - AI 自动为笔记打标签和分类
总结
通过这个完整的项目实践,我们展示了 Claude Code 如何成为开发者的得力助手:
- 加速开发 - 快速生成样板代码和重复性代码
- 知识库 - 随时提供技术文档和最佳实践
- 代码审查 - 发现潜在问题和安全隐患
- 优化建议 - 提供性能优化和重构方案
- 学习工具 - 解释复杂概念和技术原理
但要注意:
- AI 生成的代码需要人工审查
- 复杂的业务逻辑仍需人类设计
- 测试和调试是不可省略的步骤
- 理解代码原理比单纯复制更重要
AI 辅助编程的未来已经到来,关键在于如何与 AI 有效协作,而不是被 AI 替代。 Claude Code 是我们的编程伙伴,而不是替代者 - 它放大了我们的能力,但最终的创造力和判断力仍然掌握在开发者手中。
希望这篇文章能帮助你更好地理解如何使用 Claude Code 进行实际项目开发。你可以在 GitHub 查看完整源码,或者访问 在线演示 体验这个应用。
相关资源:
标签: #Claude-Code #PWA #JavaScript #AI-Coding #Web-Development #Offline-First #Markdown #JSON-Visualization