File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 2020---
2121
2222<!-- COVERAGE_START -->
23- ![ English Coverage] ( https://img.shields.io/badge/en_coverage-97 %25-green.svg ) 494/510 docs translated
23+ ![ English Coverage] ( https://img.shields.io/badge/en_coverage-84 %25-green.svg ) 494/588 docs translated
2424<!-- COVERAGE_END -->
2525
2626## 这是什么项目
Original file line number Diff line number Diff line change 11<script setup lang="ts">
22import { ref , onMounted , onBeforeUnmount } from ' vue'
3- import { useRouter } from ' vitepress '
3+ import { subscribeAfterRouteChange } from ' ../router-hooks '
44
55// 顶部阅读进度条:滚动时按 scrollTop / (scrollHeight - clientHeight) 算百分比。
66// brand 渐变 + 钢蓝微光,固定在视口顶部。路由切换 rAF+300ms 双重重算(短页归零坑)。
77// scroll/resize 用 rAF 合并,一帧最多算一次(比 anatomy 原版无节流更省,审计点名的性能债)。
88const progress = ref (0 )
9- const router = useRouter ()
109let raf: number | null = null
1110
1211function update() {
@@ -28,11 +27,11 @@ onMounted(() => {
2827 window .addEventListener (' resize' , scheduleUpdate , { passive: true })
2928})
3029
31- router . onAfterRouteChange = () => {
30+ subscribeAfterRouteChange ( () => {
3231 // 路由切换:新页 DOM 立即可测 + 300ms 后(图片/mermaid 撑高)再补一次,防短页/异步内容归零失败
3332 requestAnimationFrame (update )
3433 setTimeout (update , 300 )
35- }
34+ })
3635
3736onBeforeUnmount (() => {
3837 if (raf !== null ) cancelAnimationFrame (raf )
Original file line number Diff line number Diff line change 11import { nextTick , onMounted } from 'vue'
2- import { useRouter } from 'vitepress '
2+ import { subscribeAfterRouteChange } from './router-hooks '
33
44// mermaid 的 API 形状(只取我们用到的两个方法),避免依赖整包类型
55type MermaidApi = {
@@ -79,9 +79,9 @@ function escapeHtml(s: string) {
7979}
8080
8181export function setupMermaid ( ) {
82- const router = useRouter ( )
83-
82+ // 用订阅器而非直接赋值 router.onAfterRouteChange:后者是单值属性,
83+ // 会被 ReadingProgress 等组件覆盖,导致 SPA 跳转后 mermaid 不渲染。
8484 // .catch 治「静默失败」:之前 onMounted 调用没接住 reject,加载失败时图直接消失无痕。
8585 onMounted ( ( ) => renderMermaidDiagrams ( ) . catch ( ( e ) => console . error ( '[mermaid] onMounted 渲染失败' , e ) ) )
86- router . onAfterRouteChange = ( ) => renderMermaidDiagrams ( ) . catch ( ( e ) => console . error ( '[mermaid] 路由切换渲染失败' , e ) )
86+ subscribeAfterRouteChange ( ( ) => renderMermaidDiagrams ( ) . catch ( ( e ) => console . error ( '[mermaid] 路由切换渲染失败' , e ) ) )
8787}
Original file line number Diff line number Diff line change 1+ import { useRouter } from 'vitepress'
2+
3+ // VitePress 的 router.onAfterRouteChange 是单值属性,不是事件订阅:
4+ // 任意组件再赋值就会覆盖前一个。曾经 ReadingProgress 和 mermaid 各自赋值,
5+ // 导致 SPA 跳转后 mermaid 不渲染(首屏 onMounted 路径正常,跳转路径被覆盖)。
6+ // 这里包一层订阅器:第一次订阅时安装一个 dispatcher,之后所有订阅者共享。
7+ type RouteHandler = ( href : string ) => void
8+
9+ const subscribers = new Set < RouteHandler > ( )
10+ let installed = false
11+
12+ export function subscribeAfterRouteChange ( fn : RouteHandler ) : void {
13+ subscribers . add ( fn )
14+ if ( installed ) return
15+ // 必须在 setup 上下文调用(mermaid 的 setupMermaid / 各组件 setup 均满足)。
16+ const router = useRouter ( )
17+ router . onAfterRouteChange = ( href : string ) => {
18+ for ( const fn of subscribers ) {
19+ try {
20+ fn ( href )
21+ } catch ( e ) {
22+ // 单个订阅者抛错不能连累其它订阅者(否则 mermaid 渲染失败会让进度条也不更新)。
23+ console . error ( '[router-hook] onAfterRouteChange 订阅者抛错' , e )
24+ }
25+ }
26+ }
27+ installed = true
28+ }
You can’t perform that action at this time.
0 commit comments