# 需求文档

## 简介

Argon 主题使用 PJAX 实现无刷新页面跳转和 LazyLoad 实现图片懒加载。通过深入分析 argontheme.js（3700+ 行）的实际代码实现，发现了以下关键问题：

**PJAX 问题（2550-2700 行）：**
- `pjax:complete` 和 `pjax:end` 中重复调用 `waterflowInit()` 和 `lazyloadInit()`
- `pjax:beforeReplace` 清理资源但可能遗漏某些实例
- GT4 验证码在 `pjax:end` 中重置逻辑复杂，可能状态残留
- 滚动位置恢复使用全局变量 `pjaxScrollTop`，在快速切换时可能不准确

**LazyLoad 问题（2304-2430 行）：**
- `lazyloadInit()` 每次都创建新的 Observer，但清理时机依赖 PJAX 事件
- 图片加载效果使用 `setTimeout`，与浏览器渲染不同步
- 降级方案直接加载所有图片，缺少渐进式加载
- 图片状态重置（opacity、transform、transition）可能与 CSS 冲突

**性能问题：**
- 事件监听器可能重复绑定（scroll、resize 等）
- 图片预加载使用 `new Image()` 但无缓存机制
- `waterflowInit()` 在多个地方被调用，可能导致重复计算

本规范旨在优化这些功能，提升主题的稳定性和性能。

## 术语表

- **PJAX**: 一种结合 pushState 和 AJAX 的技术，实现无刷新页面跳转
- **LazyLoad**: 图片懒加载技术，延迟加载视口外的图片
- **IntersectionObserver**: 浏览器 API，用于监测元素与视口的交叉状态
- **Observer**: LazyLoad 使用的 IntersectionObserver 实例（全局变量 `lazyloadObserver`）
- **Zoomify**: 图片放大查看功能（全局数组 `zoomifyInstances`）
- **Waterflow**: 瀑布流布局
- **GT4**: 极验第四代验证码
- **Mobile_Catalog**: 移动端文章目录
- **NProgress**: 页面加载进度条库

## 需求

### 需求 1: PJAX 重复初始化消除

**用户故事:** 作为主题开发者，我希望消除 PJAX 事件中的重复初始化调用，以提升页面切换性能。

#### 验收标准

1. WHEN PJAX 页面切换完成 THEN THE System SHALL 确保 `waterflowInit()` 只被调用一次
2. WHEN PJAX 页面切换完成 THEN THE System SHALL 确保 `lazyloadInit()` 只被调用一次
3. WHEN PJAX 页面切换完成 THEN THE System SHALL 确保 `zoomifyInit()` 只被调用一次
4. WHEN 分析 `pjax:complete` 和 `pjax:end` 事件处理器 THEN THE System SHALL 识别所有重复调用
5. WHEN 优化后 THEN THE System SHALL 保持功能正确性的同时减少初始化次数

### 需求 2: LazyLoad Observer 生命周期管理

**用户故事:** 作为用户，我希望图片懒加载功能在 PJAX 页面切换后能正确工作，且不会出现 Observer 泄漏。

#### 验收标准

1. WHEN `lazyloadInit()` 被调用 THEN THE System SHALL 检查全局变量 `lazyloadObserver` 是否已存在
2. WHEN `lazyloadObserver` 已存在 THEN THE System SHALL 先调用 `disconnect()` 再创建新实例
3. WHEN PJAX 触发 `beforeReplace` 事件 THEN THE System SHALL 断开 Observer 并清空全局引用
4. WHEN 浏览器不支持 IntersectionObserver THEN THE System SHALL 使用滚动监听降级方案
5. WHEN Observer 清理完成 THEN THE System SHALL 确保没有内存泄漏

### 需求 3: 图片加载效果优化

**用户故事:** 作为用户，我希望图片加载时有流畅的视觉效果，不会出现闪烁或跳动。

#### 验收标准

1. WHEN 图片加载完成时 THEN THE System SHALL 使用 `requestAnimationFrame` 而非 `setTimeout` 应用效果
2. WHEN 应用 fadeIn 效果时 THEN THE System SHALL 使用 CSS transition 实现平滑过渡
3. WHEN 应用 slideDown 效果时 THEN THE System SHALL 使用 CSS transform 实现硬件加速
4. WHEN 图片加载失败时 THEN THE System SHALL 显示原始 src 并停止重试
5. WHEN 清理图片状态时 THEN THE System SHALL 移除所有 `lazyload-style-*` 类名

### 需求 4: GT4 验证码状态管理优化

**用户故事:** 作为用户，我希望在 PJAX 页面切换后验证码能正确重置和重新初始化。

#### 验收标准

1. WHEN PJAX 触发 `end` 事件且页面包含 `#geetest-captcha` THEN THE System SHALL 重置验证码状态变量
2. WHEN 重置验证码状态 THEN THE System SHALL 清空所有隐藏字段（lot_number、captcha_output、pass_token、gen_time）
3. WHEN 重置验证码状态 THEN THE System SHALL 清空验证码容器 DOM
4. WHEN 验证码容器清空后 THEN THE System SHALL 调用初始化函数重新加载验证码
5. WHEN 验证码初始化失败 THEN THE System SHALL 记录警告但不影响页面其他功能

### 需求 5: 滚动位置管理优化

**用户故事:** 作为用户，我希望在 PJAX 页面切换时滚动位置能正确恢复或重置。

#### 验收标准

1. WHEN PJAX 开始加载新页面 THEN THE System SHALL 根据链接类型决定是否记录滚动位置
2. WHEN 用户点击分页链接 THEN THE System SHALL 记录目标滚动位置到全局变量 `pjaxScrollTop`
3. WHEN PJAX 完成页面切换 THEN THE System SHALL 根据 `pjaxScrollTop` 值恢复滚动位置
4. WHEN 滚动位置恢复后 THEN THE System SHALL 重置 `pjaxScrollTop` 为 0
5. WHEN Banner 设置为封面模式 THEN THE System SHALL 根据页面类型调整滚动位置计算逻辑

### 需求 6: Zoomify 实例清理优化

**用户故事:** 作为主题开发者，我希望在 PJAX 页面切换时完整清理 Zoomify 实例，避免内存泄漏。

#### 验收标准

1. WHEN PJAX 触发 `beforeReplace` 事件 THEN THE System SHALL 遍历全局数组 `zoomifyInstances`
2. WHEN 遍历 Zoomify 实例 THEN THE System SHALL 检查实例是否存在 `destroy` 方法
3. WHEN 实例存在 `destroy` 方法 THEN THE System SHALL 调用该方法销毁实例
4. WHEN 所有实例销毁完成 THEN THE System SHALL 清空 `zoomifyInstances` 数组
5. WHEN 清理完成 THEN THE System SHALL 移除所有 `.zoomify-initialized` 类名

### 需求 7: Tippy 实例清理优化

**用户故事:** 作为主题开发者，我希望在 PJAX 页面切换时清理 Tippy 提示框实例，避免残留。

#### 验收标准

1. WHEN PJAX 触发 `beforeReplace` 事件 THEN THE System SHALL 检查 `tippy` 是否已定义
2. WHEN `tippy` 已定义 THEN THE System SHALL 查找所有 `[data-tippy-root]` 元素
3. WHEN 找到 Tippy 元素 THEN THE System SHALL 调用元素的 `_tippy.destroy()` 方法
4. WHEN 销毁完成 THEN THE System SHALL 移除所有 `.tippy-initialized` 类名
5. WHEN 销毁过程出错 THEN THE System SHALL 捕获异常并继续处理其他实例

### 需求 8: 移动端目录初始化修复

**用户故事:** 作为移动端用户，我希望在 PJAX 页面切换后文章目录能正确显示和工作。

#### 验收标准

1. WHEN PJAX 触发 `end` 事件 THEN THE System SHALL 检查 `window.resetMobileCatalog` 函数是否存在
2. WHEN 函数存在 THEN THE System SHALL 在 100ms 延迟后调用该函数
3. WHEN 重置目录状态 THEN THE System SHALL 清理旧目录相关 DOM 和事件
4. WHEN 页面需要目录 THEN THE System SHALL 重新初始化移动端目录
5. WHEN 页面不需要目录 THEN THE System SHALL 确保目录相关元素被隐藏或移除

### 需求 9: 事件监听器防重复绑定

**用户故事:** 作为主题开发者，我希望事件监听器能正确管理，避免内存泄漏和重复绑定。

#### 验收标准

1. WHEN 绑定滚动事件监听器时 THEN THE System SHALL 使用命名函数而非匿名函数
2. WHEN PJAX 清理资源时 THEN THE System SHALL 移除所有已绑定的事件监听器
3. WHEN 重新初始化功能时 THEN THE System SHALL 检查事件监听器是否已存在
4. WHEN 使用事件委托时 THEN THE System SHALL 在父元素上绑定而非每个子元素
5. WHEN 页面卸载时 THEN THE System SHALL 清理所有残留的事件监听器

### 需求 10: 图片预加载缓存机制

**用户故事:** 作为用户，我希望图片预加载能使用浏览器缓存，避免重复加载。

#### 验收标准

1. WHEN `loadImage()` 函数创建临时 Image 对象 THEN THE System SHALL 检查浏览器缓存
2. WHEN 图片已在缓存中 THEN THE System SHALL 直接使用缓存而非重新下载
3. WHEN 图片加载完成 THEN THE System SHALL 确保浏览器已缓存该图片
4. WHEN 图片加载失败 THEN THE System SHALL 不进行重试以避免浪费带宽
5. WHEN 使用预加载 THEN THE System SHALL 利用浏览器原生缓存机制而非自建缓存
