4.2 KiB
4.2 KiB
博客目录高亮逻辑优化
版本: v1.0
日期: 2026-05-06
状态: ✅ 已修复
一、问题描述
1.1 现象
博客正文页右侧目录的高亮逻辑存在边界问题:当点击小标题(H3)时,页面正确滚动到该位置,但目录实际高亮的是上方的大标题(H2)。
1.2 复现步骤
- 访问博客文章(如
/posts/hermes-chrome-opencode-ai-agent-bug) - 找到一个小标题(H3)和它上方的大标题(H2)非常接近的章节
- 点击目录中的小标题
- 观察右侧目录的高亮状态
预期行为:小标题被高亮
实际行为:大标题被高亮
1.3 影响范围
- 影响所有博客文章页
- 影响标题间距较小的章节
二、根因分析
2.1 原始代码
function updateTocHighlight() {
let current = '';
headings.forEach(heading => {
const rect = heading.getBoundingClientRect();
if (rect.top <= 80) {
current = heading.id;
}
});
}
2.2 问题根因
- 当点击小标题(H3)时,H3 滚动到
rect.top = 80(scroll-margin-top) - 由于滚动精度问题,H3 的
rect.top可能是80.5或81 - 原逻辑使用
<= 80判断,H3 不满足条件 - 而上方的 H2 满足条件(
rect.top <= 80) - 结果高亮选中了 H2
核心问题:阈值判断是硬性的,没有考虑滚动精度误差。
三、解决方案
3.1 方案对比
| 方案 | 实现 | 优点 | 缺点 |
|---|---|---|---|
| A. 扩大阈值 | <= 82 |
简单 | 仍可能有边界问题 |
| B. 距离最近算法 | 选择距离 80px 最近的标题 | 精确 | 稍复杂 |
| C. 滚动后手动设置 | 点击时直接设置高亮 | 确定性高 | 需要额外逻辑 |
3.2 采用方案:距离最近算法
原理:遍历所有标题,找到距离目标位置(80px)最近的那个标题。
实现:
function updateTocHighlight() {
const SCROLL_OFFSET = 80;
let current = '';
let minDistance = Infinity;
headings.forEach(heading => {
const rect = heading.getBoundingClientRect();
// 只考虑在视口上方或接近顶部的标题
if (rect.top <= SCROLL_OFFSET + 20) {
// 计算距离目标位置的绝对值
const distance = Math.abs(rect.top - SCROLL_OFFSET);
// 选择距离最近的标题
if (distance < minDistance) {
minDistance = distance;
current = heading.id;
}
}
});
}
优点:
- 精确:选择距离目标位置最近的标题
- 鲁棒:不受滚动精度影响
- 直观:符合用户预期
四、实现细节
4.1 修改文件
blog/templates/post.html:修改updateTocHighlight()函数
4.2 算法说明
- 目标位置:
SCROLL_OFFSET = 80px(导航栏高度 64px + 留白 16px) - 候选范围:
rect.top <= SCROLL_OFFSET + 20(即 <= 100px) - 选择标准:
Math.abs(rect.top - SCROLL_OFFSET)最小的标题
4.3 边界情况
- 标题在视口上方(rect.top < 0):距离计算为
|负数 - 80|,值较大,不会被选中 - 标题恰好在 80px:距离为 0,优先选中
- 标题在 80px 以下:不满足
<= 100条件,不参与计算
五、测试验证
5.1 测试用例
| 编号 | 测试步骤 | 预期结果 |
|---|---|---|
| T-001 | 点击 H3 标题(与 H2 间距 < 50px) | H3 被高亮 |
| T-002 | 点击 H2 标题 | H2 被高亮 |
| T-003 | 滚动页面(不点击) | 最接近顶部的标题被高亮 |
| T-004 | 快速连续点击多个标题 | 每次点击后高亮正确 |
5.2 验证方法
- 部署后访问博客文章
- 找到 H2 和 H3 间距较小的章节
- 点击目录中的 H3
- 确认 H3 被高亮(而非 H2)
六、优先级与排期
| 优先级 | 任务 | 状态 |
|---|---|---|
| P0 | 修改高亮算法 | ✅ 已完成 |
| P1 | 测试验证 | 待部署后验证 |
附录
A. 相关文件
blog/templates/post.html:目录生成和高亮逻辑