fix(embed): scroll freeze — pointer pause leaked when release happened outside window
Root cause: pointerup/pointercancel bound only on the viewport element; press on a photo then release outside the 195x280 window (or gesture interruption) never cleared the 'pointer' pause reason -> auto-scroll stopped permanently until page refresh. - pointerdown now setPointerCapture (release guaranteed to return) - window-level pointerup/pointercancel + blur fallbacks clear the reason - rAF frame wrapped in try/catch so a single bad frame can no longer break the animation chain Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -219,6 +219,14 @@ function onPointerDown(event: PointerEvent): void {
|
||||
const anchor = (event.target as HTMLElement).closest<HTMLElement>('a.stream-photo');
|
||||
lockedTarget = anchor === null ? null : (anchor.dataset.photoId ?? null);
|
||||
setReason('pointer', true);
|
||||
// 指针捕获(滚动卡死修复 2026-09-23):按下后拖出窗外松开时 viewport 收不到
|
||||
// pointerup,'pointer' 暂停原因会永久残留 → 滚动停死。捕获后 up/cancel 必回
|
||||
// 本元素;window 级兜底监听(onMounted)双保险。
|
||||
try {
|
||||
viewportEl.value?.setPointerCapture(event.pointerId);
|
||||
} catch {
|
||||
/* 指针已释放等:忽略 */
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerMove(event: PointerEvent): void {
|
||||
@@ -336,8 +344,21 @@ function onFocusOut(): void {
|
||||
}, RESUME_DELAY_MS);
|
||||
}
|
||||
|
||||
// window 级兜底(滚动卡死修复 2026-09-23):pointerup 落在窗外/别的元素、
|
||||
// 或整个 iframe 失焦(弹框抢焦点)时也要清 pointer 原因,避免暂停态永久卡住。
|
||||
function onWindowPointerEnd(): void {
|
||||
if (pointerDownY !== null) onPointerUp();
|
||||
}
|
||||
function onWindowBlur(): void {
|
||||
pointerDownY = null;
|
||||
setReason('pointer', false);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||
window.addEventListener('pointerup', onWindowPointerEnd);
|
||||
window.addEventListener('pointercancel', onWindowPointerEnd);
|
||||
window.addEventListener('blur', onWindowBlur);
|
||||
onVisibilityChange();
|
||||
if (typeof IntersectionObserver !== 'undefined' && viewportEl.value !== null) {
|
||||
visibilityObserver = new IntersectionObserver(
|
||||
@@ -354,6 +375,9 @@ onBeforeUnmount(() => {
|
||||
setReason('destroyed', true);
|
||||
layerEl.value?.clear();
|
||||
document.removeEventListener('visibilitychange', onVisibilityChange);
|
||||
window.removeEventListener('pointerup', onWindowPointerEnd);
|
||||
window.removeEventListener('pointercancel', onWindowPointerEnd);
|
||||
window.removeEventListener('blur', onWindowBlur);
|
||||
visibilityObserver?.disconnect();
|
||||
if (resumeTimer !== null) clearTimeout(resumeTimer);
|
||||
if (manualClearTimer !== null) clearTimeout(manualClearTimer);
|
||||
|
||||
Reference in New Issue
Block a user