From e2c9e0f06d8c1dbd81b1c07077dc31eeb95a0ac3 Mon Sep 17 00:00:00 2001 From: kuyua9 <948423378@qq.com> Date: Tue, 12 May 2026 18:10:42 +0800 Subject: [PATCH] fix: keep reading bookmarks bound to route --- .../theme/components/ReadingProgress.vue | 58 ++++++++++++------- .../.vitepress/theme/utils/readingBookmark.js | 18 ++++++ .../theme/utils/readingBookmark.test.js | 39 +++++++++++++ 3 files changed, 93 insertions(+), 22 deletions(-) diff --git a/docs/.vitepress/theme/components/ReadingProgress.vue b/docs/.vitepress/theme/components/ReadingProgress.vue index ca5b931..3583926 100644 --- a/docs/.vitepress/theme/components/ReadingProgress.vue +++ b/docs/.vitepress/theme/components/ReadingProgress.vue @@ -43,7 +43,7 @@ import { computed, nextTick, ref, onMounted, onUnmounted, watch } from 'vue' import { useRoute } from 'vitepress' import { - createReadingBookmark, + createReadingBookmarkSnapshot, readReadingBookmark, writeReadingBookmark } from '../utils/readingBookmark.js' @@ -125,24 +125,40 @@ const progressTitle = computed(() => : `${bookmarkTitle.value} · 阅读进度 ${progress.value}%` ) -const saveBookmark = () => { +const clearBookmarkSaveTimer = () => { + if (saveTimer) { + window.clearTimeout(saveTimer) + saveTimer = null + } +} + +const clearClickSaveTimer = () => { + if (clickSaveTimer) { + window.clearTimeout(clickSaveTimer) + clickSaveTimer = null + } +} + +const saveBookmark = (path = currentPath()) => { writeReadingBookmark( getClientStorage(), - createReadingBookmark({ - path: currentPath(), - title: articleTitle.value, - section: activeSection.value, - scrollY: window.scrollY, - progress: progress.value + createReadingBookmarkSnapshot({ + path, + getTitle: () => articleTitle.value, + getSection: () => activeSection.value, + getScrollY: () => window.scrollY, + getProgress: () => progress.value }) ) } const scheduleBookmarkSave = () => { - if (saveTimer) { - window.clearTimeout(saveTimer) - } - saveTimer = window.setTimeout(saveBookmark, 180) + const path = currentPath() + clearBookmarkSaveTimer() + saveTimer = window.setTimeout(() => { + saveTimer = null + saveBookmark(path) + }, 180) } const updateProgress = () => { @@ -325,12 +341,12 @@ const handleClick = () => { behavior: 'smooth' }) - if (clickSaveTimer) { - window.clearTimeout(clickSaveTimer) - } + const path = currentPath() + clearClickSaveTimer() clickSaveTimer = window.setTimeout(() => { + clickSaveTimer = null updateProgress() - saveBookmark() + saveBookmark(path) }, 400) } @@ -344,15 +360,11 @@ onUnmounted(() => { if (scrollTimer) { clearTimeout(scrollTimer) } - if (saveTimer) { - clearTimeout(saveTimer) - } + clearBookmarkSaveTimer() if (restoreTimer) { clearTimeout(restoreTimer) } - if (clickSaveTimer) { - clearTimeout(clickSaveTimer) - } + clearClickSaveTimer() // 清理拖拽事件 document.removeEventListener('mousemove', onDrag) document.removeEventListener('mouseup', endDrag) @@ -366,6 +378,8 @@ onUnmounted(() => { watch( () => route.path, () => { + clearBookmarkSaveTimer() + clearClickSaveTimer() resetRouteState() restoreBookmark() } diff --git a/docs/.vitepress/theme/utils/readingBookmark.js b/docs/.vitepress/theme/utils/readingBookmark.js index 0b3be38..e47a503 100644 --- a/docs/.vitepress/theme/utils/readingBookmark.js +++ b/docs/.vitepress/theme/utils/readingBookmark.js @@ -27,6 +27,24 @@ export const createReadingBookmark = ({ updatedAt: now() }) + +export const createReadingBookmarkSnapshot = ({ + path, + getTitle = () => '', + getSection = () => '', + getScrollY = () => 0, + getProgress = () => 0, + now = () => Date.now() +}) => + createReadingBookmark({ + path, + title: getTitle(), + section: getSection(), + scrollY: getScrollY(), + progress: getProgress(), + now + }) + const normalizeBookmark = ( value, expectedPath, diff --git a/docs/.vitepress/theme/utils/readingBookmark.test.js b/docs/.vitepress/theme/utils/readingBookmark.test.js index 82c9890..fd47186 100644 --- a/docs/.vitepress/theme/utils/readingBookmark.test.js +++ b/docs/.vitepress/theme/utils/readingBookmark.test.js @@ -3,6 +3,7 @@ import { describe, it } from 'node:test' import { createReadingBookmark, + createReadingBookmarkSnapshot, getReadingBookmarkKey, readReadingBookmark, writeReadingBookmark @@ -62,6 +63,44 @@ describe('reading bookmarks', () => { ) }) + + it('keeps delayed saves bound to the path captured before navigation', () => { + const storage = createStorage() + let currentPath = '/easy-vibe/zh-cn/page-a/' + + const scheduledPath = currentPath + currentPath = '/easy-vibe/zh-cn/page-b/' + + writeReadingBookmark( + storage, + createReadingBookmarkSnapshot({ + path: scheduledPath, + getTitle: () => '页面 A', + getSection: () => '小节 A', + getScrollY: () => 240, + getProgress: () => 32, + now: () => 777 + }) + ) + + assert.equal( + readReadingBookmark(storage, currentPath, 1000), + null + ) + assert.deepEqual( + readReadingBookmark(storage, scheduledPath, 1000), + { + version: 1, + path: scheduledPath, + title: '页面 A', + section: '小节 A', + scrollY: 240, + progress: 32, + updatedAt: 777 + } + ) + }) + it('normalizes invalid numeric values', () => { assert.deepEqual( createReadingBookmark({