82 lines
3.4 KiB
Markdown
82 lines
3.4 KiB
Markdown
|
|
# 修复文档链接匹配逻辑计划
|
|||
|
|
|
|||
|
|
## 1. 问题分析
|
|||
|
|
用户反馈点击 `rhi/buffer/d3d12/buffer.md` 中的 `[Initialize](initialize.md)` 链接时,错误跳转到了 `Logger::Initialize`(可能位于其他目录)。
|
|||
|
|
经过检查 `src/components/ApiDocViewer.tsx` 中的 `handleReferenceClick` 方法:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
const handleReferenceClick = useCallback((href: string) => {
|
|||
|
|
const ref = href.replace(/\.md$/, '')
|
|||
|
|
const match = externalDocs.find(d => {
|
|||
|
|
const docPath = d.relativePath.replace(/\.md$/, '')
|
|||
|
|
return docPath === ref || docPath.endsWith('/' + ref.split('/').pop())
|
|||
|
|
})
|
|||
|
|
if (match) {
|
|||
|
|
setSelectedPath(match.relativePath)
|
|||
|
|
setCurrentContent(match.content)
|
|||
|
|
}
|
|||
|
|
}, [externalDocs])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
当前的匹配逻辑非常危险:`docPath.endsWith('/' + ref.split('/').pop())` 这一行意味着只要文件名匹配(例如 `initialize.md`),不管它在哪个目录下,都可能被匹配到。这导致了跨目录的同名文件匹配错误。
|
|||
|
|
|
|||
|
|
## 2. 修复方案
|
|||
|
|
|
|||
|
|
### 修改文件: `src/components/ApiDocViewer.tsx`
|
|||
|
|
|
|||
|
|
我们需要实现基于当前文档路径的相对路径解析逻辑。由于 `handleReferenceClick` 目前只接收 `href`,我们需要让它知道当前所在的文档路径(`selectedPath`),以便正确解析相对路径。
|
|||
|
|
|
|||
|
|
1. **依赖当前路径**:确保 `handleReferenceClick` 能访问到 `selectedPath`。
|
|||
|
|
2. **实现相对路径解析**:
|
|||
|
|
- 如果链接以 `/` 开头,视为基于文档根目录的绝对路径。
|
|||
|
|
- 如果是相对路径(`./`、`../` 或直接文件名),则基于当前文档的目录进行解析。
|
|||
|
|
- 解析出目标文件的完整 `relativePath` 后,再在 `externalDocs` 中查找精确匹配。
|
|||
|
|
|
|||
|
|
**修改后的逻辑伪代码**:
|
|||
|
|
```typescript
|
|||
|
|
const handleReferenceClick = useCallback((href: string) => {
|
|||
|
|
// 1. 获取当前文档所在的目录
|
|||
|
|
const currentDir = selectedPath ? selectedPath.split('/').slice(0, -1).join('/') : '';
|
|||
|
|
|
|||
|
|
// 2. 解析目标路径
|
|||
|
|
let targetPath = '';
|
|||
|
|
if (href.startsWith('/')) {
|
|||
|
|
// 绝对路径(相对于文档根目录)
|
|||
|
|
targetPath = href.slice(1);
|
|||
|
|
} else {
|
|||
|
|
// 相对路径处理
|
|||
|
|
const parts = currentDir ? currentDir.split('/') : [];
|
|||
|
|
const hrefParts = href.split('/');
|
|||
|
|
|
|||
|
|
for (const part of hrefParts) {
|
|||
|
|
if (part === '.') continue;
|
|||
|
|
if (part === '..') {
|
|||
|
|
parts.pop();
|
|||
|
|
} else {
|
|||
|
|
parts.push(part);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
targetPath = parts.join('/');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 规范化目标路径(移除 .md 后缀以便对比,或者直接对比全名)
|
|||
|
|
// 考虑到 externalDocs 中的 relativePath 包含 .md,我们也应该构造包含 .md 的路径
|
|||
|
|
if (!targetPath.endsWith('.md')) {
|
|||
|
|
targetPath += '.md';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 精确查找
|
|||
|
|
const match = externalDocs.find(d => d.relativePath === targetPath);
|
|||
|
|
|
|||
|
|
if (match) {
|
|||
|
|
setSelectedPath(match.relativePath)
|
|||
|
|
setCurrentContent(match.content)
|
|||
|
|
} else {
|
|||
|
|
console.warn(`Document not found: ${targetPath}`);
|
|||
|
|
}
|
|||
|
|
}, [externalDocs, selectedPath]) // 添加 selectedPath 依赖
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 3. 影响与验证
|
|||
|
|
- **影响**:修复了所有相对路径链接的跳转逻辑,不再会出现跨目录同名文件乱跳的情况。
|
|||
|
|
- **验证**:点击 `rhi/buffer/d3d12/buffer.md` 中的 `initialize.md`,应该正确跳转到同目录下的 `rhi/buffer/d3d12/initialize.md`。
|