前言
本文详细讲解了文章列表功能的实现,完整项目可参考github
从0开始手把手教你做极客园项目(三)——发布文章功能实现
从0开始手把手教你做极客园项目(二)——首页功能实现
从0开始手把手教你做极客园项目(一)——登录功能实现
1.静态结构准备
在article文件夹新建一个index.tsx文件,创建模拟数据和antd组件模板
import { Link } from 'react-router-dom'
import { Card, Breadcrumb, Form, Button, Radio, DatePicker, Select } from 'antd'
import locale from 'antd/es/date-picker/locale/zh_CN'//引入汉化包
import { Table, Tag, Space } from 'antd'
import { EditOutlined, DeleteOutlined } from '@ant-design/icons'
import img404 from '@/assets/error.png'
const { Option } = Select
const { RangePicker } = DatePicker
const Article = () => {
// 准备列数据
const columns = [
{
title: '封面',
dataIndex: 'cover',
width: 120,
render: (cover: { images: any[] }) => {
return <img src={cover.images[0] || img404} width={80} height={60} alt="" />
}
},
{
title: '标题',
dataIndex: 'title',
width: 220
},
{
title: '状态',
dataIndex: 'status',
render: (data: any) => <Tag color="green">审核通过</Tag>
},
{
title: '发布时间',
dataIndex: 'pubdate'
},
{
title: '阅读数',
dataIndex: 'read_count'
},
{
title: '评论数',
dataIndex: 'comment_count'
},
{
title: '点赞数',
dataIndex: 'like_count'
},
{
title: '操作',
render: (data: any) => {
return (
<Space size="middle">
<Button type="primary" shape="circle" icon={<EditOutlined />} />
<Button
type="primary"
danger
shape="circle"
icon={<DeleteOutlined />}
/>
</Space>
)
}
}
]
// 准备表格body数据
const data = [
{
id: '8218',
comment_count: 0,
cover: {
images: [],
},
like_count: 0,
pubdate: '2019-03-11 09:00:00',
read_count: 2,
status: 2,
title: 'wkwebview离线化加载h5资源解决方案'
}
]
return (
<div>
<Card
title={
<Breadcrumb items={[
{ title: <Link to={'/'}>首页</Link> },
{ title: '文章列表' },
]} />
}
style={{ marginBottom: 20 }}
>
<Form initialValues={{ status: '' }}>
<Form.Item label="状态" name="status">
<Radio.Group>
<Radio value={''}>全部</Radio>
<Radio value={0}>草稿</Radio>
<Radio value={2}>审核通过</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="频道" name="channel_id">
<Select
placeholder="请选择文章频道"
defaultValue="lucy"
style={{ width: 120 }}
>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
</Select>
</Form.Item>
<Form.Item label="日期" name="date">
{/* 传入locale属性 控制中文显示*/}
<RangePicker locale={locale}></RangePicker>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" style={{ marginLeft: 40 }}>
筛选
</Button>
</Form.Item>
</Form>
</Card>
<Card title={`根据筛选条件共查询到 count 条结果:`}>
<Table rowKey="id" columns={columns} dataSource={data} />
</Card>
</div>
)
}
export default Article
2.封装自定义hook
由于频道列表重复渲染,有三种方式实现,一是在之前发布文章的时候的获取频道列表渲染的代码重新写一份,但是这样代码的复用性不是很高,二是在redux里存入状态数据,比较复杂,三是封装自定义hook用户通过解构获得数据,这里采用的是第三种方法
在src新建一个hooks文件夹,添加useChannel.tsx的文件,把之前写的获取频道列表数据的代码粘贴过来
import { getChannelAPI } from "@/apis/article"
import { Channel } from "@/pages/Publish"
import { useEffect, useState } from "react"
function useChannels() {
const [channels, setchannels] = useState<Channel[]>([])
useEffect(() => {
const channel = async () => {
const res = await getChannelAPI()
setchannels(res.data.channels)
}
channel()
}, [])
return {channels}
}
export {useChannels}
把之前调用频道列表的代码改写,在需要新获取频道列表数据的地方使用自定义hook获取数据
const { channels } = useChannels()
<Select
placeholder="请选择文章频道"
defaultValue="lucy"
style={{ width: 120 }}
>
{channels.map(item=><Option value={item.id}>{item.name}</Option>)}
</Select>
3.渲染文章列表
首先封装一个获取列表数据的api,在apis/articles里添加
export function getArticleAPI(){
return request({
url:'/mp/articles',
method:'GET',
})
}
然后在article的组件里利用useState将获取的数据存入,并且通过useEffect异步获取数据
const [list,setlist]=useState([])
useEffect(()=>{
async function getList() {
const res=await getArticleAPI()
setlist(res.data.results)
}
getList()
},[])
<Card title={`根据筛选条件共查询到 ${list.length} 条结果:`}>
<Table rowKey="id" columns={columns} dataSource={list} />
</Card>
4.状态适配
在文章刚发布的时候显示待审核,等到后端设置时间过去时变成审核通过,需要在原来文章组件中修改审核状态字段为三元运算,data为后端返回的status数据1和2,1表示待审核,2表示审核通过
{
title: '状态',
dataIndex: 'status',
//data为后端返回的状态status
render: (data:number) => <Tag color={data===1?'warning':'success'}>{data===1?'待审核':'审核通过'}</Tag>
},
5.筛选功能实现
给form表单添加一个onFinish方法,指定获取表单value的类型ValueInterface
const [reqdata,setdata]=useState({
status:'',
channel_id:'',
begin_pubdate:'',
end_pubdate:'',
page:1,
per_page:4
})
const onfinish=(value:ValueInterface)=>{
setdata(
{
...reqdata,
channel_id:value.channel_id,
status:value.status,
begin_pubdate:value.date[0].format('YYYY-MM-DD'),
end_pubdate:value.date[1].format('YYYY-MM-DD')
}
)
}
interface ValueInterface {
channel_id: string;
status: string;
date: [moment.Moment, moment.Moment];
}
但是这个moment库需要在命令行下载
npm install moment --legacy-peer-deps
在渲染列表的useEffect函数中添加依赖数组reqdata,这样当我们提交数据时将获取的参数传给后端
useEffect(()=>{
async function getList() {
const res=await getArticleAPI(reqdata)
setlist(res.data.results)
}
getList()
},[reqdata])
6.分页功能实现
在table里添加组件的pagination属性,包括总共的数量和每页的数量来自动划分页数,并且添加一个事件改变函数,当切换不同页数时,根据页数的不同来重新渲染列表
<Card title={`根据筛选条件共查询到 ${count} 条结果:`}>
<Table rowKey="id" columns={columns} dataSource={list} pagination={
{
total: count,
pageSize: reqdata.per_page,
onChange: onchange
}
} />
</Card>
const onchange = (page: number) => {
setdata({
...reqdata,
page
})
}
总结
本次文章列表实现了渲染,筛选,分页的逻辑,并且对一些功能做了一些优化,明天将会是极客园项目的最后一篇,喜欢的小伙伴点点关注,点点赞