mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 03:06:38 +08:00
bug处理
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { shouldRememberScroll } from './useScrollMemory.ts'
|
import { shouldPersistScrollSample, shouldRememberScroll } from './useScrollMemory.ts'
|
||||||
|
|
||||||
function check(name: string, condition: boolean) {
|
function check(name: string, condition: boolean) {
|
||||||
if (!condition) throw new Error(`useScrollMemory: ${name}`)
|
if (!condition) throw new Error(`useScrollMemory: ${name}`)
|
||||||
@@ -11,4 +11,41 @@ check('media detail remembers scroll', shouldRememberScroll('/media/media-1'))
|
|||||||
check('settings does not remember scroll', !shouldRememberScroll('/settings'))
|
check('settings does not remember scroll', !shouldRememberScroll('/settings'))
|
||||||
check('player does not remember scroll', !shouldRememberScroll('/play/media-1'))
|
check('player does not remember scroll', !shouldRememberScroll('/play/media-1'))
|
||||||
|
|
||||||
|
check(
|
||||||
|
'route transition collapse is ignored',
|
||||||
|
!shouldPersistScrollSample({
|
||||||
|
current: 0,
|
||||||
|
lastSaved: 1800,
|
||||||
|
height: 400,
|
||||||
|
lastHeight: 4200,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
check(
|
||||||
|
'intentional scroll to top is persisted',
|
||||||
|
shouldPersistScrollSample({
|
||||||
|
current: 0,
|
||||||
|
lastSaved: 1800,
|
||||||
|
height: 4200,
|
||||||
|
lastHeight: 4200,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
check(
|
||||||
|
'normal downward scroll is persisted',
|
||||||
|
shouldPersistScrollSample({
|
||||||
|
current: 1900,
|
||||||
|
lastSaved: 1800,
|
||||||
|
height: 4200,
|
||||||
|
lastHeight: 4200,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
check(
|
||||||
|
'content growth still allows persist',
|
||||||
|
shouldPersistScrollSample({
|
||||||
|
current: 1800,
|
||||||
|
lastSaved: 1800,
|
||||||
|
height: 5200,
|
||||||
|
lastHeight: 4200,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
console.log('useScrollMemory.test.ts ok')
|
console.log('useScrollMemory.test.ts ok')
|
||||||
|
|||||||
@@ -39,6 +39,23 @@ export function shouldRememberScroll(pathname: string): boolean {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路由切换时 Outlet 内容变矮,浏览器会把共享滚动容器的 scrollTop 钳低,
|
||||||
|
* 并可能同步触发 scroll 事件。这种“假滚动”不能写入存储,否则返回时永远回到顶部。
|
||||||
|
*/
|
||||||
|
export function shouldPersistScrollSample(input: {
|
||||||
|
current: number
|
||||||
|
lastSaved: number
|
||||||
|
height: number
|
||||||
|
lastHeight: number
|
||||||
|
}): boolean {
|
||||||
|
const { current, lastSaved, height, lastHeight } = input
|
||||||
|
if (height + 1 < lastHeight && current < lastSaved) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记住列表页的滚动位置。页面内容会异步长高,因此恢复期间会监听内容高度,
|
* 记住列表页的滚动位置。页面内容会异步长高,因此恢复期间会监听内容高度,
|
||||||
* 直到目标位置可达;期间用户主动滚动会立即接管,避免和恢复逻辑抢滚动条。
|
* 直到目标位置可达;期间用户主动滚动会立即接管,避免和恢复逻辑抢滚动条。
|
||||||
@@ -61,6 +78,7 @@ export function useScrollMemory(pathname: string, userKey = 'anonymous'): void {
|
|||||||
let restoreFrame = 0
|
let restoreFrame = 0
|
||||||
let restorePumpUntil = 0
|
let restorePumpUntil = 0
|
||||||
let lastSaved = saved
|
let lastSaved = saved
|
||||||
|
let lastHeight = el.scrollHeight
|
||||||
|
|
||||||
const stopRestore = () => {
|
const stopRestore = () => {
|
||||||
if (restoreFrame) {
|
if (restoreFrame) {
|
||||||
@@ -80,6 +98,7 @@ export function useScrollMemory(pathname: string, userKey = 'anonymous'): void {
|
|||||||
restoring = false
|
restoring = false
|
||||||
stopRestore()
|
stopRestore()
|
||||||
lastSaved = Math.round(el.scrollTop)
|
lastSaved = Math.round(el.scrollTop)
|
||||||
|
lastHeight = el.scrollHeight
|
||||||
writeScrollPosition(key, lastSaved)
|
writeScrollPosition(key, lastSaved)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +127,19 @@ export function useScrollMemory(pathname: string, userKey = 'anonymous'): void {
|
|||||||
const saveNow = () => {
|
const saveNow = () => {
|
||||||
if (restoring) return
|
if (restoring) return
|
||||||
const current = Math.round(el.scrollTop)
|
const current = Math.round(el.scrollTop)
|
||||||
|
const height = el.scrollHeight
|
||||||
|
if (
|
||||||
|
!shouldPersistScrollSample({
|
||||||
|
current,
|
||||||
|
lastSaved,
|
||||||
|
height,
|
||||||
|
lastHeight,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
lastHeight = height
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastHeight = height
|
||||||
if (current === lastSaved) return
|
if (current === lastSaved) return
|
||||||
lastSaved = current
|
lastSaved = current
|
||||||
writeScrollPosition(key, current)
|
writeScrollPosition(key, current)
|
||||||
@@ -118,6 +150,7 @@ export function useScrollMemory(pathname: string, userKey = 'anonymous'): void {
|
|||||||
restoring = false
|
restoring = false
|
||||||
stopRestore()
|
stopRestore()
|
||||||
lastSaved = Math.round(el.scrollTop)
|
lastSaved = Math.round(el.scrollTop)
|
||||||
|
lastHeight = el.scrollHeight
|
||||||
writeScrollPosition(key, lastSaved)
|
writeScrollPosition(key, lastSaved)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +205,8 @@ export function useScrollMemory(pathname: string, userKey = 'anonymous'): void {
|
|||||||
window.removeEventListener('touchstart', cancelRestore, true)
|
window.removeEventListener('touchstart', cancelRestore, true)
|
||||||
window.removeEventListener('keydown', onKeyDown, true)
|
window.removeEventListener('keydown', onKeyDown, true)
|
||||||
stopRestore()
|
stopRestore()
|
||||||
|
// 清理时写入最后一次有效位置,避免依赖已被钳制的 el.scrollTop。
|
||||||
|
writeScrollPosition(key, lastSaved)
|
||||||
}
|
}
|
||||||
}, [pathname, userKey])
|
}, [pathname, userKey])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user