From 0e94c5ecda35b8aab93ebaddcea20ab339ef477b Mon Sep 17 00:00:00 2001 From: zhanglun Date: Mon, 1 Jan 2024 18:31:54 +0800 Subject: [PATCH] fix: scroll into view when article selected --- src/components/ArticleList/index.tsx | 6 +-- src/hooks/useAutoScroll.ts | 72 ---------------------------- src/layout/Article/Layout1.tsx | 43 ++++++++++++++++- 3 files changed, 45 insertions(+), 76 deletions(-) delete mode 100644 src/hooks/useAutoScroll.ts diff --git a/src/components/ArticleList/index.tsx b/src/components/ArticleList/index.tsx index 8f0f48d9d..fa0578ddd 100644 --- a/src/components/ArticleList/index.tsx +++ b/src/components/ArticleList/index.tsx @@ -26,7 +26,7 @@ export interface ArticleListRefType { innerRef: React.RefObject; } -export const ArticleList = React.memo((props: ArticleListProps) => { +export const ArticleList = React.memo(React.forwardRef((props: ArticleListProps, ref) => { const { articles, isEmpty, isLoading, isReachingEnd, size, setSize } = props; const loadRef = useRef(null); const entry = useIntersectionObserver(loadRef, {}); @@ -54,7 +54,7 @@ export const ArticleList = React.memo((props: ArticleListProps) => { }, [loadRefVisible, isReachingEnd]); return ( -
+
{isEmpty ? (
@@ -80,4 +80,4 @@ export const ArticleList = React.memo((props: ArticleListProps) => {
); -}); +})); diff --git a/src/hooks/useAutoScroll.ts b/src/hooks/useAutoScroll.ts deleted file mode 100644 index 67a4a1d15..000000000 --- a/src/hooks/useAutoScroll.ts +++ /dev/null @@ -1,72 +0,0 @@ -import React, { useEffect } from "react"; -import { useBearStore } from "@/stores"; -import { Article } from "@/db"; - -export interface UseAutoScrollProps { - listRef?: any; -} - -export const useAutoScroll = (props: UseAutoScrollProps) => { - const { listRef } = props; - const store = useBearStore((state) => ({ - articleList: state.articleList, - })); - - function calculateItemPosition( - direction: "up" | "down", - article: Article | null, - ) { - if (!article?.uuid) { - return; - } - - const $li = document.getElementById(article.uuid); - const bounding = $li?.getBoundingClientRect(); - const winH = window.innerHeight; - - if ( - (direction === "up" || direction === "down") && - bounding && - bounding.top < 58 - ) { - const offset = 58 - bounding.top; - const scrollTop = (listRef?.current?.scrollTop || 0) - offset; - - listRef?.current?.scrollTo(0, scrollTop); - } else if ( - (direction === "up" || direction === "down") && - bounding && - bounding.bottom > winH - ) { - const offset = bounding.bottom - winH; - const scrollTop = (listRef?.current?.scrollTop || 0) + offset; - - console.log( - "🚀 ~ file: index.tsx:324 ~ ArticleContainer ~ scrollTop:", - scrollTop, - ); - listRef?.current?.scrollTo(0, scrollTop); - } - } - - useEffect(() => { - // watch current idx change - const unsub2 = useBearStore.subscribe( - (state) => state.currentIdx, - (idx, previousIdx) => { - if (idx <= previousIdx) { - console.log("往上", store.articleList[idx]); - calculateItemPosition("up", store.articleList[idx]); - } else { - console.log("往下", store.articleList[idx]); - calculateItemPosition("down", store.articleList[idx]); - } - }, - ); - - return () => { - console.log("clean!!!!"); - unsub2(); - }; - }, [store.articleList]); -}; diff --git a/src/layout/Article/Layout1.tsx b/src/layout/Article/Layout1.tsx index dac9c1fe3..c8d43f090 100644 --- a/src/layout/Article/Layout1.tsx +++ b/src/layout/Article/Layout1.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { useParams } from "react-router-dom"; import { ArticleList } from "@/components/ArticleList"; import { useBearStore } from "@/stores"; @@ -29,6 +29,7 @@ export const Layout1 = React.memo( const params: { name: string } = useParams(); const [isSyncing, setIsSyncing] = useState(false); const [currentUuid, setCurrentUuid] = useState(); + const listRef = useRef(null); const store = useBearStore((state) => ({ viewMeta: state.viewMeta, @@ -98,6 +99,43 @@ export const Layout1 = React.memo( } }; + function calculateItemPosition( + direction: "up" | "down", + article: ArticleResItem | null + ) { + if (!article?.uuid) { + return; + } + + const $li = document.getElementById(article.uuid); + const bounding = $li?.getBoundingClientRect(); + const winH = window.innerHeight; + + if ( + (direction === "up" || direction === "down") && + bounding && + bounding.top < 58 + ) { + const offset = 58 - bounding.top; + const scrollTop = (listRef?.current?.scrollTop || 0) - offset; + + listRef?.current?.scrollTo(0, scrollTop); + } else if ( + (direction === "up" || direction === "down") && + bounding && + bounding.bottom > winH + ) { + const offset = bounding.bottom - winH; + const scrollTop = (listRef?.current?.scrollTop || 0) + offset; + + console.log( + "🚀 ~ file: index.tsx:324 ~ ArticleContainer ~ scrollTop:", + scrollTop + ); + listRef?.current?.scrollTo(0, scrollTop); + } + } + function goPreviousArticle() { let previousItem: ArticleResItem; let uuid = store.article?.uuid; @@ -110,6 +148,7 @@ export const Layout1 = React.memo( store.updateArticleStatus(previousItem, ArticleReadStatus.READ); setCurrentUuid((_) => previousItem.uuid); store.setArticle(previousItem); + calculateItemPosition("up", previousItem); break; } @@ -138,6 +177,7 @@ export const Layout1 = React.memo( nextItem.read_status = ArticleReadStatus.READ; store.updateArticleStatus(nextItem, ArticleReadStatus.READ); store.setArticle(nextItem); + calculateItemPosition("down", nextItem); return [false]; }; @@ -229,6 +269,7 @@ export const Layout1 = React.memo(