From 4452d39e06f5d31dc2ffbd45ebec773cc473c469 Mon Sep 17 00:00:00 2001 From: tangly1024 Date: Fri, 15 Oct 2021 13:02:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=BB=9A=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E7=BB=84=E4=BB=B6,=E9=A1=B5=E9=9D=A2=E5=BE=AE?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/BlogPost.js | 2 +- components/BlogPostList.js | 76 +++++++++++++ components/BlogPostListScrollPagination .js | 116 ++++++++++++++++++++ components/JumpToTop.js | 2 +- components/TagList.js | 2 +- layouts/IndexLayout.js | 59 +--------- layouts/PageLayout.js | 59 +--------- 7 files changed, 199 insertions(+), 117 deletions(-) create mode 100644 components/BlogPostList.js create mode 100644 components/BlogPostListScrollPagination .js diff --git a/components/BlogPost.js b/components/BlogPost.js index 3b606099..61a85868 100644 --- a/components/BlogPost.js +++ b/components/BlogPost.js @@ -4,7 +4,7 @@ import TagItemMini from '@/components/TagItemMini' const BlogPost = ({ post }) => { return (
+ className='animate__animated animate__fadeIn inline-block border dark:border-gray-600 my-2 w-full md:max-w-md bg-white dark:bg-gray-700 dark:hover:bg-gray-600 overflow-hidden'> {/* 封面图 */} {post.page_cover && post.page_cover.length > 1 && ( diff --git a/components/BlogPostList.js b/components/BlogPostList.js new file mode 100644 index 00000000..0d599954 --- /dev/null +++ b/components/BlogPostList.js @@ -0,0 +1,76 @@ +import BlogPost from '@/components/BlogPost' +import Pagination from '@/components/Pagination' +import BLOG from '@/blog.config' + +import { useRouter } from 'next/router' + +/** + * 文章列表分页表格 + * @param page 当前页 + * @param posts 所有文章 + * @param tags 所有标签 + * @returns {JSX.Element} + * @constructor + */ +const BlogPostList = ({ page = 1, posts = [], tags }) => { + if (!posts) { + return
+
+

No posts found.

+
+
+ } + let filteredBlogPosts = posts + + // 处理查询过滤 支持标签、关键词过滤 + let currentSearch = '' + const router = useRouter() + if (router.query && router.query.s) { + currentSearch = router.query.s + filteredBlogPosts = posts.filter(post => { + const tagContent = post.tags ? post.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + post.slug + return searchContent.toLowerCase().includes(currentSearch.toLowerCase()) + }) + } + + // 处理分页 + const totalPages = Math.ceil(filteredBlogPosts.length / BLOG.postsPerPage) + const postsToShow = filteredBlogPosts.slice( + BLOG.postsPerPage * (page - 1), + BLOG.postsPerPage * page + ) + let showNext = false + if (filteredBlogPosts) { + const totalPosts = filteredBlogPosts.length + showNext = page * BLOG.postsPerPage < totalPosts + } + + return
+ {(!page || page === 1) && (
)} + + {(page && page !== 1) && ( +
+
+ {page && page !== 1 && (页 {page} / {totalPages})} +
+
+ )} + +
+ {/* 文章列表 */} +
+ {!postsToShow.length && ( +

No posts found.

+ )} + {postsToShow.map(post => ( + + ))} +
+ + +
+
+} + +export default BlogPostList diff --git a/components/BlogPostListScrollPagination .js b/components/BlogPostListScrollPagination .js new file mode 100644 index 00000000..2da18c45 --- /dev/null +++ b/components/BlogPostListScrollPagination .js @@ -0,0 +1,116 @@ +import BlogPost from '@/components/BlogPost' +import Pagination from '@/components/Pagination' +import BLOG from '@/blog.config' + +import { useRouter } from 'next/router' +import { useCallback, useEffect, useState } from 'react' +import throttle from 'lodash.throttle' + +/** + * 获取指定页码的文章 + * @param page 第几页 + * @param totalPosts 所有文章 + * @param postsPerPage 每页文章数量 + * @returns {*} + */ +const getPostByPage = function (page, totalPosts, postsPerPage) { + return totalPosts.slice( + postsPerPage * (page - 1), + postsPerPage * page + ) +} + +/** + * 博客列表滚动分页 + * @param posts 所有文章 + * @param tags 所有标签 + * @returns {JSX.Element} + * @constructor + */ +const BlogPostListScrollPagination = ({ posts = [], tags, targetRef }) => { + if (!posts) { + return
+
+

No posts found.

+
+
+ } + let filteredBlogPosts = posts + + // 处理查询过滤 支持标签、关键词过滤 + let currentSearch = '' + const router = useRouter() + if (router.query && router.query.s) { + currentSearch = router.query.s + filteredBlogPosts = posts.filter(post => { + const tagContent = post.tags ? post.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + post.slug + return searchContent.toLowerCase().includes(currentSearch.toLowerCase()) + }) + } + const [page, updatePage] = useState(1) + const [postsToShow, updatePostToShow] = useState(getPostByPage(page, filteredBlogPosts, BLOG.postsPerPage)) + + let showNext = false + if (filteredBlogPosts) { + const totalPosts = filteredBlogPosts.length + showNext = page * BLOG.postsPerPage < totalPosts + } + const [loading, updateLoading] = useState(false) + const handleGetMore = function () { + if (!showNext) { + // 完了 + return + } + if (loading) { + // 加载中 + return + } + updateLoading(true) + updatePage(page + 1) + updatePostToShow(postsToShow.concat(getPostByPage(page + 1, filteredBlogPosts, BLOG.postsPerPage))) + updateLoading(false) + } + + // 监听滚动自动分页加载 + const scrollTrigger = useCallback(throttle(() => { + const scrollS = window.scrollY + window.outerHeight + const clientHeight = targetRef ? (targetRef.current.clientHeight) : 0 + if (scrollS > clientHeight + 10) { + handleGetMore() + } + }, 500)) + + // 监听滚动 + useEffect(() => { + window.addEventListener('scroll', scrollTrigger) + return () => { + window.removeEventListener('scroll', scrollTrigger) + } + }) + + return
+
+ {/* 文章列表 */} +
+ {!postsToShow.length && ( +

No posts found.

+ )} + {postsToShow.map(post => ( + + ))} +
+ +
+ {showNext + ? (
加载更多
) + : ( +
加载完了😰
+ )} + +
+
+
+} + +export default BlogPostListScrollPagination diff --git a/components/JumpToTop.js b/components/JumpToTop.js index 4acc8b6d..3dfcd209 100644 --- a/components/JumpToTop.js +++ b/components/JumpToTop.js @@ -34,7 +34,7 @@ const JumpToTop = ({ targetRef, showPercent = true }) => { return (
+ className={(show ? 'animate__fadeInUp' : 'animate__fadeOutUp') + ' rounded-full animate__animated animate__faster shadow-xl'}>
{ {Object.keys(tags).map(tag => { const selected = tag === currentTag return ( - + ) })}
diff --git a/layouts/IndexLayout.js b/layouts/IndexLayout.js index 56043739..668718ba 100644 --- a/layouts/IndexLayout.js +++ b/layouts/IndexLayout.js @@ -1,8 +1,5 @@ -import BlogPost from '@/components/BlogPost' import PropTypes from 'prop-types' -import Pagination from '@/components/Pagination' import BLOG from '@/blog.config' -import { useRouter } from 'next/router' import TagsBar from '@/components/TagsBar' import Footer from '@/components/Footer' import React, { useRef } from 'react' @@ -10,6 +7,7 @@ import Container from '@/components/Container' import JumpToTop from '@/components/JumpToTop' import SideBar from '@/components/SideBar' import TopNav from '@/components/TopNav' +import BlogPostListScrollPagination from '@/components/BlogPostListScrollPagination ' const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => { const meta = { @@ -17,34 +15,6 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => { type: 'website', ...customMeta } - page = page ?? 1 - let postsToShow = [] - let filteredBlogPosts = posts ?? [] - let currentSearch = '' - if (posts) { - const router = useRouter() - if (router.query && router.query.s) { - currentSearch = router.query.s - filteredBlogPosts = posts.filter(post => { - const tagContent = post.tags ? post.tags.join(' ') : '' - const searchContent = post.title + post.summary + tagContent + post.slug - return searchContent.toLowerCase().includes(currentSearch.toLowerCase()) - }) - } - } - const totalPages = Math.ceil(filteredBlogPosts.length / BLOG.postsPerPage) - - if (posts) { - postsToShow = filteredBlogPosts.slice( - BLOG.postsPerPage * (page - 1), - BLOG.postsPerPage * page - ) - } - let showNext = false - if (filteredBlogPosts) { - const totalPosts = filteredBlogPosts.length - showNext = page * BLOG.postsPerPage < totalPosts - } const targetRef = useRef(null) @@ -57,32 +27,7 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => {
-
- {(!page || page === 1) && (
)} - - {/* 当前搜索 */} - {(currentSearch || (page && page !== 1)) && ( -
-
- {page && page !== 1 && (页 {page} / {totalPages})} -
-
- )} - -
- {/* 文章列表 */} -
- {!postsToShow.length && ( -

No posts found.

- )} - {postsToShow.map(post => ( - - ))} -
- - -
-
+
diff --git a/layouts/PageLayout.js b/layouts/PageLayout.js index 0bf94333..c67ab706 100644 --- a/layouts/PageLayout.js +++ b/layouts/PageLayout.js @@ -1,8 +1,5 @@ -import BlogPost from '@/components/BlogPost' import PropTypes from 'prop-types' -import Pagination from '@/components/Pagination' import BLOG from '@/blog.config' -import { useRouter } from 'next/router' import TagsBar from '@/components/TagsBar' import Footer from '@/components/Footer' import React, { useRef } from 'react' @@ -10,6 +7,7 @@ import Container from '@/components/Container' import JumpToTop from '@/components/JumpToTop' import SideBar from '@/components/SideBar' import TopNav from '@/components/TopNav' +import BlogPostList from '@/components/BlogPostList' const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => { const meta = { @@ -17,34 +15,6 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => { type: 'website', ...customMeta } - page = page ?? 1 - let postsToShow = [] - let filteredBlogPosts = posts ?? [] - let currentSearch = '' - if (posts) { - const router = useRouter() - if (router.query && router.query.s) { - currentSearch = router.query.s - filteredBlogPosts = posts.filter(post => { - const tagContent = post.tags ? post.tags.join(' ') : '' - const searchContent = post.title + post.summary + tagContent + post.slug - return searchContent.toLowerCase().includes(currentSearch.toLowerCase()) - }) - } - } - const totalPages = Math.ceil(filteredBlogPosts.length / BLOG.postsPerPage) - - if (posts) { - postsToShow = filteredBlogPosts.slice( - BLOG.postsPerPage * (page - 1), - BLOG.postsPerPage * page - ) - } - let showNext = false - if (filteredBlogPosts) { - const totalPosts = filteredBlogPosts.length - showNext = page * BLOG.postsPerPage < totalPosts - } const targetRef = useRef(null) return ( @@ -58,32 +28,7 @@ const IndexLayout = ({ tags, posts, page, currentTag, ...customMeta }) => { -
- {(!page || page === 1) && (
)} - - {/* 当前搜索 */} - {(currentSearch || (page && page !== 1)) && ( -
-
- {page && page !== 1 && (页 {page} / {totalPages})} -
-
- )} - -
- {/* 文章列表 */} -
- {!postsToShow.length && ( -

No posts found.

- )} - {postsToShow.map(post => ( - - ))} -
- - -
-
+