Merge pull request #92 from kuyua9/fix/reading-bookmark-route-save-kuyua9
fix: keep reading bookmarks bound to route
This commit is contained in:
@@ -43,7 +43,7 @@
|
|||||||
import { computed, nextTick, ref, onMounted, onUnmounted, watch } from 'vue'
|
import { computed, nextTick, ref, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import { useRoute } from 'vitepress'
|
import { useRoute } from 'vitepress'
|
||||||
import {
|
import {
|
||||||
createReadingBookmark,
|
createReadingBookmarkSnapshot,
|
||||||
readReadingBookmark,
|
readReadingBookmark,
|
||||||
writeReadingBookmark
|
writeReadingBookmark
|
||||||
} from '../utils/readingBookmark.js'
|
} from '../utils/readingBookmark.js'
|
||||||
@@ -125,24 +125,40 @@ const progressTitle = computed(() =>
|
|||||||
: `${bookmarkTitle.value} · 阅读进度 ${progress.value}%`
|
: `${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(
|
writeReadingBookmark(
|
||||||
getClientStorage(),
|
getClientStorage(),
|
||||||
createReadingBookmark({
|
createReadingBookmarkSnapshot({
|
||||||
path: currentPath(),
|
path,
|
||||||
title: articleTitle.value,
|
getTitle: () => articleTitle.value,
|
||||||
section: activeSection.value,
|
getSection: () => activeSection.value,
|
||||||
scrollY: window.scrollY,
|
getScrollY: () => window.scrollY,
|
||||||
progress: progress.value
|
getProgress: () => progress.value
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const scheduleBookmarkSave = () => {
|
const scheduleBookmarkSave = () => {
|
||||||
if (saveTimer) {
|
const path = currentPath()
|
||||||
window.clearTimeout(saveTimer)
|
clearBookmarkSaveTimer()
|
||||||
}
|
saveTimer = window.setTimeout(() => {
|
||||||
saveTimer = window.setTimeout(saveBookmark, 180)
|
saveTimer = null
|
||||||
|
saveBookmark(path)
|
||||||
|
}, 180)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateProgress = () => {
|
const updateProgress = () => {
|
||||||
@@ -325,12 +341,12 @@ const handleClick = () => {
|
|||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
})
|
})
|
||||||
|
|
||||||
if (clickSaveTimer) {
|
const path = currentPath()
|
||||||
window.clearTimeout(clickSaveTimer)
|
clearClickSaveTimer()
|
||||||
}
|
|
||||||
clickSaveTimer = window.setTimeout(() => {
|
clickSaveTimer = window.setTimeout(() => {
|
||||||
|
clickSaveTimer = null
|
||||||
updateProgress()
|
updateProgress()
|
||||||
saveBookmark()
|
saveBookmark(path)
|
||||||
}, 400)
|
}, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,15 +360,11 @@ onUnmounted(() => {
|
|||||||
if (scrollTimer) {
|
if (scrollTimer) {
|
||||||
clearTimeout(scrollTimer)
|
clearTimeout(scrollTimer)
|
||||||
}
|
}
|
||||||
if (saveTimer) {
|
clearBookmarkSaveTimer()
|
||||||
clearTimeout(saveTimer)
|
|
||||||
}
|
|
||||||
if (restoreTimer) {
|
if (restoreTimer) {
|
||||||
clearTimeout(restoreTimer)
|
clearTimeout(restoreTimer)
|
||||||
}
|
}
|
||||||
if (clickSaveTimer) {
|
clearClickSaveTimer()
|
||||||
clearTimeout(clickSaveTimer)
|
|
||||||
}
|
|
||||||
// 清理拖拽事件
|
// 清理拖拽事件
|
||||||
document.removeEventListener('mousemove', onDrag)
|
document.removeEventListener('mousemove', onDrag)
|
||||||
document.removeEventListener('mouseup', endDrag)
|
document.removeEventListener('mouseup', endDrag)
|
||||||
@@ -366,6 +378,8 @@ onUnmounted(() => {
|
|||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
() => {
|
() => {
|
||||||
|
clearBookmarkSaveTimer()
|
||||||
|
clearClickSaveTimer()
|
||||||
resetRouteState()
|
resetRouteState()
|
||||||
restoreBookmark()
|
restoreBookmark()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,24 @@ export const createReadingBookmark = ({
|
|||||||
updatedAt: now()
|
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 = (
|
const normalizeBookmark = (
|
||||||
value,
|
value,
|
||||||
expectedPath,
|
expectedPath,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { describe, it } from 'node:test'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
createReadingBookmark,
|
createReadingBookmark,
|
||||||
|
createReadingBookmarkSnapshot,
|
||||||
getReadingBookmarkKey,
|
getReadingBookmarkKey,
|
||||||
readReadingBookmark,
|
readReadingBookmark,
|
||||||
writeReadingBookmark
|
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', () => {
|
it('normalizes invalid numeric values', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
createReadingBookmark({
|
createReadingBookmark({
|
||||||
|
|||||||
Reference in New Issue
Block a user