Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
---

<!-- COVERAGE_START -->
![English Coverage](https://img.shields.io/badge/en_coverage-97%25-green.svg) 494/510 docs translated
![English Coverage](https://img.shields.io/badge/en_coverage-84%25-green.svg) 494/588 docs translated
<!-- COVERAGE_END -->

## 这是什么项目
Expand Down
7 changes: 3 additions & 4 deletions site/.vitepress/theme/components/ReadingProgress.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vitepress'
import { subscribeAfterRouteChange } from '../router-hooks'

// 顶部阅读进度条:滚动时按 scrollTop / (scrollHeight - clientHeight) 算百分比。
// brand 渐变 + 钢蓝微光,固定在视口顶部。路由切换 rAF+300ms 双重重算(短页归零坑)。
// scroll/resize 用 rAF 合并,一帧最多算一次(比 anatomy 原版无节流更省,审计点名的性能债)。
const progress = ref(0)
const router = useRouter()
let raf: number | null = null

function update() {
Expand All @@ -28,11 +27,11 @@ onMounted(() => {
window.addEventListener('resize', scheduleUpdate, { passive: true })
})

router.onAfterRouteChange = () => {
subscribeAfterRouteChange(() => {
// 路由切换:新页 DOM 立即可测 + 300ms 后(图片/mermaid 撑高)再补一次,防短页/异步内容归零失败
requestAnimationFrame(update)
setTimeout(update, 300)
}
})

onBeforeUnmount(() => {
if (raf !== null) cancelAnimationFrame(raf)
Expand Down
8 changes: 4 additions & 4 deletions site/.vitepress/theme/mermaid-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { nextTick, onMounted } from 'vue'
import { useRouter } from 'vitepress'
import { subscribeAfterRouteChange } from './router-hooks'

// mermaid 的 API 形状(只取我们用到的两个方法),避免依赖整包类型
type MermaidApi = {
Expand Down Expand Up @@ -79,9 +79,9 @@ function escapeHtml(s: string) {
}

export function setupMermaid() {
const router = useRouter()

// 用订阅器而非直接赋值 router.onAfterRouteChange:后者是单值属性,
// 会被 ReadingProgress 等组件覆盖,导致 SPA 跳转后 mermaid 不渲染。
// .catch 治「静默失败」:之前 onMounted 调用没接住 reject,加载失败时图直接消失无痕。
onMounted(() => renderMermaidDiagrams().catch((e) => console.error('[mermaid] onMounted 渲染失败', e)))
router.onAfterRouteChange = () => renderMermaidDiagrams().catch((e) => console.error('[mermaid] 路由切换渲染失败', e))
subscribeAfterRouteChange(() => renderMermaidDiagrams().catch((e) => console.error('[mermaid] 路由切换渲染失败', e)))
}
28 changes: 28 additions & 0 deletions site/.vitepress/theme/router-hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useRouter } from 'vitepress'

// VitePress 的 router.onAfterRouteChange 是单值属性,不是事件订阅:
// 任意组件再赋值就会覆盖前一个。曾经 ReadingProgress 和 mermaid 各自赋值,
// 导致 SPA 跳转后 mermaid 不渲染(首屏 onMounted 路径正常,跳转路径被覆盖)。
// 这里包一层订阅器:第一次订阅时安装一个 dispatcher,之后所有订阅者共享。
type RouteHandler = (href: string) => void

const subscribers = new Set<RouteHandler>()
let installed = false

export function subscribeAfterRouteChange(fn: RouteHandler): void {
subscribers.add(fn)
if (installed) return
// 必须在 setup 上下文调用(mermaid 的 setupMermaid / 各组件 setup 均满足)。
const router = useRouter()
router.onAfterRouteChange = (href: string) => {
for (const fn of subscribers) {
try {
fn(href)
} catch (e) {
// 单个订阅者抛错不能连累其它订阅者(否则 mermaid 渲染失败会让进度条也不更新)。
console.error('[router-hook] onAfterRouteChange 订阅者抛错', e)
}
}
}
installed = true
}
Loading