From 5eefcc3c41c5ce38dbc07ea32f65cb0e62ddc98a Mon Sep 17 00:00:00 2001 From: Christins Date: Tue, 20 Oct 2026 08:08:57 +0800 Subject: [PATCH] feat: enhance ArticleList and IndexPage with scrollable layout support --- .../articleList/ArticleList.module.css | 17 +++++++++++++ src/components/articleList/ArticleList.tsx | 24 +++++++++++++++---- src/pages/home/IndexPage.module.css | 2 +- src/pages/home/IndexPage.tsx | 1 + 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/components/articleList/ArticleList.module.css b/src/components/articleList/ArticleList.module.css index c571a36..1d6d62c 100644 --- a/src/components/articleList/ArticleList.module.css +++ b/src/components/articleList/ArticleList.module.css @@ -34,6 +34,23 @@ gap: 1rem; } +/* 胶囊布局:标题/搜索栏和分页固定,仅卡片区域滚动 */ +.articleListScrollable .listHeader { + flex: 0 0 auto; +} + +.articleListScrollable .articles { + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; +} + +.articleListScrollable .pagination { + flex: 0 0 auto; +} + /* 当文章数量少于每页数量时,用占位空间填充 */ .articles::after { content: ""; diff --git a/src/components/articleList/ArticleList.tsx b/src/components/articleList/ArticleList.tsx index f33e60c..6fd43a2 100644 --- a/src/components/articleList/ArticleList.tsx +++ b/src/components/articleList/ArticleList.tsx @@ -24,9 +24,19 @@ interface ArticleListProps { categoryName?: string; searchKeyword?: string; headerRight?: React.ReactNode; + /** 胶囊布局下让标题/搜索栏与分页固定,仅卡片区域滚动 */ + scrollable?: boolean; } -const ArticleList: React.FC = ({ labelId, labelName, categoryId, categoryName, searchKeyword, headerRight }) => { +const ArticleList: React.FC = ({ + labelId, + labelName, + categoryId, + categoryName, + searchKeyword, + headerRight, + scrollable = false, +}) => { const [searchParams, setSearchParams] = useSearchParams(); const currentPage = parseInt(searchParams.get("page") || "1", 10); const itemsPerPage = 6; @@ -35,11 +45,12 @@ const ArticleList: React.FC = ({ labelId, labelName, categoryI const [loading, setLoading] = useState(true); const navigate = useNavigate(); const { t } = useTranslation("article"); + const articlesRef = useRef(null); // 切换页码 const handlePageChange = (page: number) => { setSearchParams({ page: String(page) }); - // 滚动到顶部 + // 经典布局滚动窗口;胶囊布局由下方 effect 重置卡片区域 window.scrollTo({ top: 0, behavior: "smooth" }); }; @@ -155,6 +166,11 @@ const ArticleList: React.FC = ({ labelId, labelName, categoryI }; }, [currentPage, labelId, categoryId, searchKeyword, t]); + // 筛选或翻页后让卡片区域回到顶部 + useEffect(() => { + articlesRef.current?.scrollTo({ top: 0 }); + }, [currentPage, labelId, categoryId, searchKeyword]); + const totalPages = Math.ceil(totalArticles / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + articles.length; @@ -190,7 +206,7 @@ const ArticleList: React.FC = ({ labelId, labelName, categoryI }; return ( -
+

{labelName @@ -201,7 +217,7 @@ const ArticleList: React.FC = ({ labelId, labelName, categoryI

{headerRight &&
{headerRight}
}
-
+
{loading ? ( Array.from({ length: 5 }, (_, index) => (
diff --git a/src/pages/home/IndexPage.module.css b/src/pages/home/IndexPage.module.css index dcd6452..d2c520f 100644 --- a/src/pages/home/IndexPage.module.css +++ b/src/pages/home/IndexPage.module.css @@ -57,7 +57,7 @@ flex: 2; min-width: 0; min-height: 0; - overflow-y: auto; + overflow: hidden; display: flex; flex-direction: column; scrollbar-width: none; diff --git a/src/pages/home/IndexPage.tsx b/src/pages/home/IndexPage.tsx index d9f9f8e..6fa323f 100644 --- a/src/pages/home/IndexPage.tsx +++ b/src/pages/home/IndexPage.tsx @@ -180,6 +180,7 @@ const IndexPage: React.FC = () => { categoryId={selectedCategoryId} categoryName={selectedCategoryName} searchKeyword={searchKeyword} + scrollable headerRight={