fix: more robust continuous scroll, closes #993 (#1017)

This commit is contained in:
Huang Xin
2025-05-03 18:07:32 +08:00
committed by GitHub
parent 8167f27156
commit c9e08f2c01
3 changed files with 48 additions and 18 deletions
@@ -114,18 +114,6 @@ const FoliateViewer: React.FC<{
const detail = (event as CustomEvent).detail;
if (detail.reason !== 'scroll' && detail.reason !== 'page') return;
if (detail.reason === 'scroll') {
const renderer = viewRef.current?.renderer;
const viewSettings = getViewSettings(bookKey)!;
if (renderer && viewSettings.continuousScroll) {
if (renderer.start <= 0) {
viewRef.current?.prev(1);
// sometimes viewSize has subpixel value that the end never reaches
} else if (renderer.end + 1 >= renderer.viewSize) {
viewRef.current?.next(1);
}
}
}
const parallelViews = getParallels(bookKey);
if (parallelViews && parallelViews.size > 0) {
parallelViews.forEach((key) => {
@@ -140,7 +128,7 @@ const FoliateViewer: React.FC<{
};
const { handlePageFlip } = usePageFlip(bookKey, viewRef, containerRef);
useTouchEvent(bookKey, viewRef);
const { onTouchStart, onTouchMove, onTouchEnd } = useTouchEvent(bookKey, viewRef);
useClickEvent(bookKey, handlePageFlip);
useFoliateEvents(viewRef.current, {
@@ -226,6 +214,9 @@ const FoliateViewer: React.FC<{
<div
className='foliate-viewer h-[100%] w-[100%]'
onClick={(event) => handlePageFlip(event)}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}
ref={containerRef}
/>
</>
@@ -29,25 +29,25 @@ export const useTouchEvent = (
viewRef: React.MutableRefObject<FoliateView | null>,
) => {
const { hoveredBookKey, setHoveredBookKey, getViewSettings } = useReaderStore();
const viewSettings = getViewSettings(bookKey)!;
let touchStart: IframeTouch | null = null;
let touchEnd: IframeTouch | null = null;
const onTouchStart = (e: IframeTouchEvent) => {
const onTouchStart = (e: IframeTouchEvent | React.TouchEvent<HTMLDivElement>) => {
touchEnd = null;
const touch = e.targetTouches[0];
if (!touch) return;
touchStart = touch;
};
const onTouchMove = (e: IframeTouchEvent) => {
const onTouchMove = (e: IframeTouchEvent | React.TouchEvent<HTMLDivElement>) => {
if (!touchStart) return;
const touch = e.targetTouches[0];
if (touch) {
touchEnd = touch;
}
if (hoveredBookKey && touchEnd) {
const viewSettings = getViewSettings(bookKey)!;
const deltaY = touchEnd.screenY - touchStart.screenY;
const deltaX = touchEnd.screenX - touchStart.screenX;
if (!viewSettings!.scrolled && !viewSettings!.vertical) {
@@ -60,7 +60,7 @@ export const useTouchEvent = (
}
};
const onTouchEnd = (e: IframeTouchEvent) => {
const onTouchEnd = (e: IframeTouchEvent | React.TouchEvent<HTMLDivElement>) => {
if (!touchStart) return;
const touch = e.targetTouches[0];
@@ -70,6 +70,7 @@ export const useTouchEvent = (
const windowWidth = window.innerWidth;
if (touchEnd) {
const viewSettings = getViewSettings(bookKey)!;
const deltaY = touchEnd.screenY - touchStart.screenY;
const deltaX = touchEnd.screenX - touchStart.screenX;
// also check for deltaX to prevent swipe page turn from triggering the toggle
@@ -87,6 +88,34 @@ export const useTouchEvent = (
setHoveredBookKey(null);
}
}
const renderer = viewRef.current?.renderer;
if (renderer && viewSettings.scrolled && viewSettings.continuousScroll) {
const SCROLL_THRESHOLD = 30;
const doScroll = () => {
// may have overscroll where the start is greater than 0
if (renderer.start <= deltaY && deltaY > SCROLL_THRESHOLD) {
setTimeout(() => {
viewRef.current?.prev(renderer.start + 1);
}, 100);
// sometimes viewSize has subpixel value that the end never reaches
} else if (
Math.ceil(renderer.end) - deltaY >= renderer.viewSize &&
deltaY < -SCROLL_THRESHOLD
) {
setTimeout(() => {
viewRef.current?.next(renderer.viewSize - Math.floor(renderer.end) + 1);
}, 100);
}
};
if (renderer.size >= renderer.viewSize) {
doScroll();
} else {
const handleRelocate = () => {
doScroll();
};
renderer.addEventListener('relocate', handleRelocate, { once: true });
}
}
}
touchStart = null;
@@ -112,4 +141,10 @@ export const useTouchEvent = (
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hoveredBookKey, viewRef.current]);
return {
onTouchStart,
onTouchMove,
onTouchEnd,
};
};
+5 -1
View File
@@ -48,7 +48,11 @@ export interface FoliateView extends HTMLElement {
goTo?: (params: { index: number; anchor: number }) => void;
setStyles?: (css: string) => void;
getContents: () => { doc: Document; index?: number }[];
addEventListener: (type: string, listener: EventListener) => void;
addEventListener: (
type: string,
listener: EventListener,
option?: AddEventListenerOptions,
) => void;
removeEventListener: (type: string, listener: EventListener) => void;
};
}