自定义组件 · 连续阅读体验 · 阅读列表与仓库列表分别独立生效
Quartz v4 默认没有文章底部的上下篇导航。用户在读完一篇文章后,需要回到侧边栏或首页才能找到下一篇——这是静态博客框架(Hexo、Hugo 等)早已标配的体验,Quartz 作为知识库框架缺失了这块。
因此自定义实现了 PrevNext 组件,按日期排序提供线性阅读路径,让读者可以沉浸式连续浏览。
核心设计:全站内容按日期排序是 PrevNext 的导航基础,但通过 ConditionalRender 将渲染限定在阅读列表板块内。仓库列表页面完全不出现上下篇导航——两个内容流保持独立。
| 文件 | 作用 |
|---|---|
quartz/components/PrevNext.tsx | 核心逻辑:按日期排序全站文件,找到当前页前后位置,渲染导航链接 |
quartz/components/styles/prevNext.scss | 桌面/移动端布局,悬停效果,标题截断 |
quartz/i18n/locales/zh-CN.ts | 中文本地化:"上一篇" / "下一篇" |
quartz/i18n/locales/en-US.ts | 英文本地化:"Previous" / "Next" |
quartz.layout.ts | 布局注册:ConditionalRender 包裹,仅阅读列表生效 |
quartz/styles/custom.scss | 隐藏 Quartz 默认插入的分隔线 |
// PrevNext.tsx — section 过滤 + 全站排序 + 定位当前页
const sectionPrefix = fileData.slug?.split("/")[0] // 提取顶层目录名
const pages = allFiles
.filter((f) =>
f.dates && // 必须有日期
f.slug !== "index" && // 排除首页
!f.slug?.startsWith("tags/") && // 排除标签页
f.slug?.startsWith(sectionPrefix + "/") // 仅当前 section 的文件
)
.sort(byDateAndAlphabetical(cfg)) // 按日期降序 + 字母排序
const currentIndex = pages.findIndex((f) => f.slug === fileData.slug)
// 降序排列下,数组前一位置是更新的文章,后一位置是更老的。
// 交换索引方向使:「上一篇」→ 更老的文章,「下一篇」→ 更新的文章
const prev = pages[currentIndex + 1] // 上一篇(更老)
const next = pages[currentIndex - 1] // 下一篇(更新)
// quartz.layout.ts — afterBody 区
Component.ConditionalRender({
component: Component.PrevNext(),
condition: (page) =>
page.fileData.slug?.startsWith("阅读列表/") ||
page.fileData.slug?.startsWith("仓库列表/"),
}),
| 决策 | 选择 | 原因 |
|---|---|---|
| 是否内置 | 自定义组件 | Quartz v4 无此功能,参考博客框架体验补齐 |
| 排序依据 | 按文章 frontmatter date | 与侧边栏 Explorer 的排序保持一致,反映笔记整理顺序 |
| 作用范围 | 阅读列表 + 仓库列表 | 两个板块分别独立——各自按日期排序,互不跨越 |
| 导航方向 | 上一篇指向更老,下一篇指向更新 | 降序排列下索引互换:prev = current+1(更老),next = current-1(更新)。符合列表最新在最前的直觉 |
| 边界处理 | 首篇无「上一篇」,末篇无「下一篇」 | 自然终止,不循环,不跨板块 |
| 移动端 | 标题截断(15 字),垂直堆叠 | 小屏空间有限,长标题会撑破布局 |
| 首页/标签页 | 排除(slug !== "index") | 这些页面没有时间线概念 |