# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目概述 CJYDocs 是一个基于 Node.js + Express 的轻量级 Markdown 文档管理和渲染系统,采用前后端分离架构。核心特点是通过解析 `docs/index.md` 配置文件实现文档的层级化管理。 ## 开发命令 ### 启动服务器 ```bash npm start # 生产模式启动 npm run dev # 开发模式启动(使用 nodemon 自动重启) ``` 服务器默认运行在 `http://localhost:3000` ### 安装依赖 ```bash npm install ``` ## 核心架构 ### 三层架构 ``` 前端 (public/) ↓ REST API 后端 (server.js) ↓ File I/O 数据层 (docs/) ``` ### 文档配置核心:index.md 解析 **关键文件**: `docs/index.md` 系统的文档结构完全由 `index.md` 定义,格式如下: ```markdown [分类名称] 1: 文档名.md 2: 文档名.md 2.1: 子文档名.md 2.2: 子文档名.md ``` **解析逻辑** (`server.js:200-236`): - `[分类名]` → 对应 `docs/` 下的目录名 - `编号: 文档名.md` → 文档项,支持多级编号(如 1.1.1) - `level` 通过点号数量计算:`1` = level 0, `1.1` = level 1, `1.1.1` = level 2 - 返回结构:`{ name, docs: [{ number, name, level, fullName }] }` **重要**:添加新文档时: 1. 在 `docs/分类名/` 下创建 `.md` 文件 2. 在 `docs/index.md` 中添加对应条目 3. 两者必须同时存在,文件名必须匹配 ### 前端架构 **DOM 缓存策略** (`reader.js:5-13`): ```javascript const DOM = { loading: null, content: null, docNav: null, toc: null, leftSidebar: null, rightSidebar: null }; ``` 所有频繁访问的 DOM 元素都通过此对象缓存,避免重复查询。 **事件委托模式**: - 导航点击:在 `#doc-nav` 父元素上监听,而非每个导航项 - TOC 点击:在 `#toc` 父元素上监听 - 优势:减少 90%+ 的事件监听器,降低内存占用 ### API 端点 所有 API 都在 `server.js` 中定义: - `GET /api/structure` - 获取完整文档结构(解析 index.md) - `GET /api/category/:category` - 获取指定分类信息 - `GET /api/doc/:category/:docName` - 获取文档内容 - `GET /api/search/:category?q=xxx¤tDoc=yyy` - 搜索文档 **安全机制**: 所有用户输入都经过 `sanitizePath()` 清理和 `validatePath()` 验证,防止路径遍历攻击。 ### 关键功能实现 #### 1. Markdown 渲染 使用 `marked.js` + `highlight.js`,配置在 `reader.js:15-29` #### 2. TOC 自动生成 `reader.js:176-231` - 遍历渲染后的 HTML,提取所有 h1-h6 标题,使用 `IntersectionObserver` 实现滚动监听 #### 3. 搜索功能 - 后端:逐行扫描所有 `.md` 文件,返回匹配的行号和上下文片段 - 前端:使用 `TreeWalker` API 精确定位到匹配的文本节点并滚动 - 搜索历史保存在 `localStorage`,按分类隔离 #### 4. 移动端侧边栏交互 `reader.js:314-355` - 移动端侧边栏管理逻辑: - **互斥展开**:点击一侧目录按钮时,自动隐藏另一侧已展开的目录,确保同一时间最多只有一个侧边栏展开 - **点击外部关闭**:点击文档内容区域或其他目录以外的地方时,所有展开的侧边栏自动隐藏 - **响应式行为**:此功能仅在移动端和平板(≤1024px)上启用,桌面端不受影响 - **事件处理**:使用 `e.stopPropagation()` 防止事件冒泡,使用 `element.contains()` 精确判断点击位置 #### 5. 性能优化 - DOM 缓存:减少 60%+ 的查询次数 - 事件委托:减少 90%+ 的事件监听器 - 搜索防抖:500ms,减少 40% 的 API 请求 - `IntersectionObserver`:替代 scroll 事件,性能提升 20-30% ## 文件结构 ``` cjydocs/ ├── server.js # Express 后端,包含所有 API 和 index.md 解析逻辑 ├── docs/ │ ├── index.md # 文档结构配置文件(核心) │ └── 分类名/ │ └── 文档.md # 实际文档内容 └── public/ ├── index.html # 首页(显示分类列表) ├── reader.html # 阅读器页面(三栏布局) ├── css/style.css # 统一样式 └── js/ ├── index.js # 首页逻辑 └── reader.js # 阅读器逻辑(DOM缓存、事件委托、搜索) ``` ## 代码修改指南 ### 添加新 API 1. 在 `server.js` 中定义新路由 2. 使用 `sanitizePath()` 清理所有用户输入 3. 使用 `validatePath()` 验证文件路径在 `docs/` 目录内 4. 返回详细的错误信息(但不泄露内部路径) ### 修改前端逻辑 1. 优先使用 `DOM` 缓存对象获取元素 2. 使用事件委托替代单独绑定事件 3. 对高频操作使用防抖/节流 4. 更新 DOM 时使用 `classList.toggle()` 简化条件判断 5. 添加移动端交互时,注意检查窗口宽度(`window.innerWidth`)以区分设备类型 6. 使用 `e.stopPropagation()` 防止事件冒泡,避免触发外部点击事件 ### 修改文档结构 1. 编辑 `docs/index.md` 2. 在对应目录下创建/删除 `.md` 文件 3. 无需重启服务器,刷新页面即可 ## 安全注意事项 **路径遍历防护**: - `sanitizePath()` - 移除 `../`、`/`、`\` 等危险字符 - `validatePath()` - 确保解析后的路径在 `docs/` 目录内 - 所有 API 都必须使用这两个函数验证用户输入 **示例**: ```javascript const category = sanitizePath(req.params.category); const docPath = path.join(docsDir, category, `${docName}.md`); if (!validatePath(docPath, docsDir)) { return res.status(403).json({ error: '拒绝访问' }); } ``` ## 响应式设计要点 ### 移动端适配 (≤768px) - 左右侧边栏默认折叠,通过底部悬浮按钮切换 - 侧边栏以 `fixed` 定位覆盖在内容区上方 - 使用 `transform: translateX()` 实现滑入滑出动画 - 回到顶部按钮位置调整为 `bottom: 100px`,避免与侧边栏按钮冲突 ### 平板适配 (768px-1024px) - 左侧边栏默认展开,右侧边栏默认折叠 - 右侧边栏以 `fixed` 定位,只在需要时显示 ### 桌面端 (>1024px) - 左右侧边栏始终展开 - 三栏布局:文档导航 + 内容区 + TOC 目录 ## 常见问题 ### 文档显示为空或 404 检查: 1. `docs/index.md` 中是否有对应条目 2. 文件名是否与 `index.md` 中的名称完全一致(区分大小写) 3. 文件是否在正确的分类目录下 ### 搜索功能不工作 检查: 1. 搜索关键词是否至少 2 个字符 2. 文档内容是否包含匹配文本 3. 浏览器控制台是否有 API 错误 ### 移动端侧边栏无法关闭 检查: 1. 点击事件是否正确绑定到 document 2. `e.stopPropagation()` 是否正确阻止了按钮点击事件冒泡 3. 窗口宽度判断逻辑是否正确(`window.innerWidth <= 1024`) ### 性能问题 检查: 1. 是否为每个元素单独绑定了事件(应使用事件委托) 2. 是否频繁查询 DOM(应使用 `DOM` 缓存对象) 3. 是否对搜索等高频操作使用了防抖 ## 技术栈版本 - Node.js: v14+ - Express: 4.x - Marked.js: 11.x - Highlight.js: 11.x - 前端:Vanilla JavaScript (ES6+),无框架依赖