Skip to content

Commit a802af7

Browse files
committed
feat: cra-react18项目增加时间轴功能
fix #107
1 parent 0bce1e7 commit a802af7

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

.changeset/sixty-windows-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"cra-react18": minor
3+
---
4+
5+
feat: cra-react18项目增加时间轴功能

app/cra-react18/src/router/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ const router = createBrowserRouter([
2929
path: "/messages",
3030
lazy: () => import("../views/Messages"),
3131
},
32+
{
33+
path: "/timeline",
34+
lazy: () => import("../views/Timeline"),
35+
},
3236
]);
3337

3438
export default router;
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { useEffect, useRef, useState } from "react";
2+
import { Button, Card, Empty, Skeleton, Timeline } from "antd";
3+
import { NavLink } from "react-router-dom";
4+
import styled from "styled-components";
5+
import { ArticleDTO } from "@/bean/dto";
6+
import BaseLayout from "@/components/BaseLayout";
7+
import { articleService } from "@/services/article";
8+
import { format } from "@/utils/date-utils";
9+
import { useAsyncLoading } from "@/hooks/async";
10+
import LazyImage from "@/components/LazyImage";
11+
import BottomTips from "@/components/BottomTips";
12+
13+
const StyledTimeline = styled(Timeline)`
14+
.timeline-card {
15+
border: 0;
16+
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
17+
18+
.ant-card-body {
19+
display: flex;
20+
padding: 10px;
21+
}
22+
}
23+
${LazyImage} {
24+
width: 80px;
25+
height: 60px;
26+
object-fit: cover;
27+
}
28+
29+
.timeline-card__info {
30+
flex: 1;
31+
margin-left: 10px;
32+
font-size: 12px;
33+
overflow: hidden;
34+
35+
> time {
36+
color: #999;
37+
}
38+
39+
> h4 {
40+
margin: 3px 0;
41+
font-size: 14px;
42+
line-height: 1.2em;
43+
}
44+
45+
.category {
46+
font-weight: 700;
47+
48+
&:hover {
49+
color: #87b4e2;
50+
opacity: 0.85;
51+
}
52+
53+
+ .category::before {
54+
content: ", ";
55+
}
56+
}
57+
}
58+
`;
59+
60+
export const Component: React.FC = () => {
61+
const [articleList, setArticleList] = useState<ArticleDTO[]>([]);
62+
63+
const [pageInfo, setPageInfo] = useState({
64+
pageNo: 1,
65+
pageSize: 6,
66+
});
67+
68+
const prevPageNo = useRef(pageInfo.pageNo);
69+
70+
const [total, setTotal] = useState(0);
71+
72+
const handleGetArticleList = async (isLoadMore = false) => {
73+
const res = await articleService.page(pageInfo);
74+
const mappedData = res.data.map((item) => {
75+
return {
76+
...item,
77+
create_time: format(item.create_time),
78+
};
79+
});
80+
if (isLoadMore) {
81+
setArticleList([...articleList, ...mappedData]);
82+
} else {
83+
setArticleList(mappedData);
84+
}
85+
setTotal(res.total);
86+
};
87+
88+
const { trigger: getPageList, loading } = useAsyncLoading(handleGetArticleList, [pageInfo]);
89+
90+
useEffect(() => {
91+
const isChangePage = pageInfo.pageNo !== prevPageNo.current;
92+
getPageList(isChangePage);
93+
// eslint-disable-next-line react-hooks/exhaustive-deps
94+
}, [pageInfo.pageNo]);
95+
96+
useEffect(() => {
97+
prevPageNo.current = pageInfo.pageNo;
98+
}, [pageInfo.pageNo]);
99+
100+
const loadMore = () => {
101+
if (articleList.length < total) {
102+
setPageInfo({ ...pageInfo, pageNo: pageInfo.pageNo + 1 });
103+
}
104+
};
105+
106+
return (
107+
<BaseLayout>
108+
<>
109+
{articleList.length > 0 ? (
110+
<StyledTimeline>
111+
{articleList.map((article) => (
112+
<Timeline.Item key={article.id} color="#2b82a8">
113+
<Card className="timeline-card">
114+
<NavLink to={`/article/${article.id}`}>
115+
<LazyImage src={article.poster} />
116+
</NavLink>
117+
<div className="timeline-card__info">
118+
<time>{article.create_time}</time>
119+
<h4 className="truncate" title={article.article_name}>
120+
{article.article_name}
121+
</h4>
122+
{article.categories.map((category) => (
123+
<NavLink
124+
className="category"
125+
key={category.id}
126+
to={`/category/${encodeURIComponent(category.categoryName)}`}
127+
>
128+
<span>{category.categoryName}</span>
129+
</NavLink>
130+
))}
131+
</div>
132+
</Card>
133+
</Timeline.Item>
134+
))}
135+
</StyledTimeline>
136+
) : (
137+
<Empty />
138+
)}
139+
140+
<Skeleton loading={loading} active paragraph={{ rows: 6 }} />
141+
142+
<BottomTips>
143+
{articleList.length < total ? (
144+
<Button shape="round" type="primary" onClick={loadMore}>
145+
加载更多
146+
</Button>
147+
) : (
148+
<span>没有更多了</span>
149+
)}
150+
</BottomTips>
151+
</>
152+
</BaseLayout>
153+
);
154+
};

0 commit comments

Comments
 (0)