Feat: Pagination Component

分页器组件,日记翻页功能
This commit is contained in:
奇趣保罗 2024-01-05 01:10:21 +08:00
parent 69de4c5aad
commit 0466ee763f
3 changed files with 132 additions and 4 deletions

View File

@ -0,0 +1,74 @@
import { clsn } from "~/utils";
interface PaginationProps {
size: number;
total: number;
current: number;
onClick: (page: number) => void;
}
const genArr = (min: number, max: number) => {
const arr = [];
while (min <= max) {
arr.push(min);
min++;
}
return arr;
}
const calc = (current: number, total: number, size: number) => {
// 总页数
const totalPage = Math.ceil(total / size);
// 左右分隔多少个出现小点点
const offset = 1;
// 中间部分,只展示前后各一个分页数
const prefixEnd = current - 1;
const suffixStart = current + 1;
const suffixEnd = current + offset > totalPage ? totalPage : current + offset;
const prefixs = current > 1 ? genArr(current - offset > 0 ? current - offset : 1, prefixEnd) : [];
const suffixs = current < totalPage ? genArr(suffixStart, suffixEnd) : [];
const betweens = [
...(current > offset + 1 ? [1, "..."] : []),
...prefixs,
current,
...suffixs,
...(current > totalPage - (offset + 1) ? [] : ["...", totalPage]),
]
return betweens;
}
function Pagination({ current = 3, total, size, onClick }: PaginationProps) {
const arr = calc(current, total, size);
return (
<div>
{arr.map((item, index) => {
if (typeof item === "string") {
return <span className="p-2 mr-2">{item}</span>
}
return (
<span
key={index}
className={clsn(
"inline-block w-10 h-10 leading-[2] md:w-14 md:h-14 md:leading-[3] cursor-pointer text-center mr-2 last:mr-0 rounded-xl border-4 border-transparent hover:bg-pink-400 hover:border-b-transparent hover:text-white transition-colors",
current === item ? "bg-cyan-200 border-b-cyan-300 text-white font-bold" : "bg-white border-b-cyan-200"
)}
onClick={() => onClick(item)}
>
{item}
</span>
);
})}
</div>
);
}
export default Pagination;

View File

@ -1,7 +1,9 @@
import { Link, useLoaderData } from "@remix-run/react";
import { ChangeEvent, useEffect } from "react";
import { Link, useLoaderData, useNavigate, useSearchParams } from "@remix-run/react";
import { json, LoaderFunctionArgs, type MetaFunction } from "@remix-run/node";
import Pagination from "~/components/common/pagination";
import { clsn, siteTitle } from "~/utils";
import { getFirstImage } from "~/utils/note";
import { getFirstImage, years } from "~/utils/note";
export const meta: MetaFunction = () => {
return [
@ -17,11 +19,36 @@ export async function loader({ request }: LoaderFunctionArgs) {
const note = await fetch(`https://paul.ren/api/note/?page=${page}&year=${year}`).then((res) => res.json()) as API.PageResponse<API.Note.INoteData[]>;
return json({ note, page });
return json({ note, page, year });
}
export default function Note() {
const { note } = useLoaderData<typeof loader>();
const navigate = useNavigate();
const [params, setParams] = useSearchParams();
const { note, page, year } = useLoaderData<typeof loader>();
useEffect(() => {
console.log(note);
}, []);
const onChangeYear = (ev: ChangeEvent<HTMLSelectElement>) => {
navigate({
search: `?year=${ev.target.value}`,
});
};
const onChangePage = (value: number) => {
const year = params.get("year");
const nextParams: Record<string, string> = {
page: `${value}`,
};
if (year !== null) {
nextParams.year = year;
}
setParams(nextParams);
};
return (
<main className="px-2 py-24 max-w-3xl mx-auto">
@ -54,6 +81,18 @@ export default function Note() {
);
})}
</section>
<section className="flex gap-4 flex-col-reverse justify-between md:flex-row items-center">
<select
className="cursor-pointer px-5 py-3 rounded-xl border-4 border-transparent border-b-cyan-200 mr-8"
value={year}
onChange={onChangeYear}
>
{years.map((year) => (
<option value={year}>{year} </option>
))}
</select>
<Pagination current={Number(page)} size={7} total={note.count} onClick={onChangePage} />
</section>
</main>
);
}

View File

@ -1,3 +1,18 @@
// 日记年份
function getYears(startAt: number) {
let years: number[] = [];
let currentYear = new Date().getFullYear();
while (currentYear >= startAt) {
years.push(currentYear);
currentYear--;
}
return years;
}
export const years = getYears(2018);
// 获取第一张图片
export const getFirstImage = (note: API.Note.INoteData) => {
if (note.media && note.media.length > 0) {