功能介绍

本文记录了对 Quartz 预览气泡(Popover)进行的深度定制。通过将原生 Popover 重构为自定义组件 Custom.Popover,我们解决了预览窗口相互干扰的问题,并显著提升了锚点定位的准确性:

  1. 独立实例机制:解决了“同一个文档中多次引用同一篇文章时,预览窗口相互干扰”的问题。通过为每个链接(Pathname + Hash + ID)生成唯一标识,确保每个预览窗口拥有独立的状态和滚动位置。
  2. 鲁棒滚动定位:参考 Todo 插件的实现,引入了多次尝试滚动机制(使用 setTimeout 阶梯尝试)。有效解决了内容加载缓慢或动态渲染导致锚点定位失效的问题。
  3. 全站预览统一:不仅增强了正文中的维基链接(Wikilinks)预览,还同时优化了反向链接(Backlinks)和待办事项(Todo)的预览体验。

优化逻辑

独立 ID 生成

在原生的实现中,预览窗口仅基于路径识别(popover-${link.pathname})。当一个页面中有多个链接指向同一篇文章的不同段落时,它们会共用同一个预览窗口。

自定义版本将其修改为:

const popoverId = `popover-${link.pathname}${hash}${link.id ? "-" + link.id : ""}`

这确保了即使是同一个页面,只要锚点不同或是不同位置的引用,都能获得专属的预览视图。

阶梯式重试滚动

为了应对 Quartz 动态内容加载带来的异步问题,我们不再只在展示瞬间滚动一次,而是进行多次重试:

const scrollPopover = () => {
  // ... 执行滚动定位
}
scrollPopover()
setTimeout(scrollPopover, 50)
setTimeout(scrollPopover, 100)

如何使用

下载文件

请将以下文件保存至项目的 quartz/custom/ 对应位置:

  1. 插件文件夹Popover/
  2. 统一入口index.ts

启用插件

1. 修改全局配置 (quartz.config.ts)

禁用原生的预览功能:

// quartz.config.ts
configuration: {
  // ...
  enablePopovers: false, // 禁用默认预览气泡,使用 custom/Popover
}

2. 配置布局组件 (quartz.layout.ts)

afterBody 中注册自定义组件:

// quartz.layout.ts
import * as Custom from "./quartz/custom"
 
export const sharedPageComponents: SharedLayout = {
  // ...
  afterBody: [
    Custom.ImageZoom(),
    Custom.Popover(), // 启用增强版预览插件
    // ...
  ],
}