01-内容管理-筛选区域结构
完成内容管理筛选区域基本架子
大致步骤:
- 准备根容器间距样式
- 使用Card的组件确定区域
- 使用Breadcrumb组件作为Card组件标题
- 使用Form组件搭建筛选项目,表单元素暂时不写
核心代码:
Article/index.module.scss
.root {
padding: 24px;
}
Article/index.jsx
import { Form, Button, Card, Breadcrumb } from “antd”;
import { Link } from “react-router-dom”;
import styles from “./index.module.scss”;
const Article = () => {
return (
// 面包屑
首页
}
>
{/ 表单 /}
);
};
export default Article;
02-内容管理-筛选区域表单
完成内容管理筛选区域表单绘制
大致步骤:
- 状态使用 Radio.Group 组件
- 频道使用 Select 组件
- 日期使用 DatePicker.RangePicker 组件,需要本地化(中文)
核心代码:Article/index.jsx
- 导包
import {
Card,
Form,
+ Radio,
+ Select,
Button,
+ DatePicker,
Breadcrumb,
message,
} from “antd”;
+import “moment/locale/zh-cn”;
+import locale from “antd/es/date-picker/locale/zh_CN”;
- 状态
- 频道
- 日期
注意:Radio 选项的值是 undefined 默认选中,日期组件需要本地化 zh_CN
03-内容管理-结果区域表格
完成结果区域结构和准备表格
大致步骤:
- 使用 Card 组件搭建基本结构
- 分析 Table 组件的使用
- 使用 Table 组件完成文章列表的搭建
核心代码:
Article/index.jsx
- 使用 Card 组件搭建基本结构
根据筛选条件共查询到 100 条结果:
}style={{ marginTop: 24 }}
>
放置表格组件
- 分析 Table 组件的使用
- dataSource 属性,设置数据
- columns 属性,设置每一列的标题和显示的内容 title 表头,dataIndex 数据字段
- 如果显示的内容需要使用JSX可以使用 render 选项,使用函数返回来渲染。
- 使用 Table 组件完成文章列表的搭建
import { EditOutlined, DeleteOutlined } from “@ant-design/icons”;
import { Table, Space} from “antd”;
const columns = [
{
title: “封面”,
dataIndex: “cover”,
key: “cover”,
render: () => ‘自定义封面’,
},
{
title: “标题”,
dataIndex: “title”,
key: “title”,
},
{
title: “状态”,
dataIndex: “status”,
key: “status”,
render: () => ‘自定义状态’,
},
{
title: “发布时间”,
dataIndex: “pubdate”,
key: “pubdate”,
},
{
title: “阅读数”,
dataIndex: “read_count”,
key: “read_count”,
},
{
title: “评论数”,
dataIndex: “comment_count”,
key: “comment_count”,
},
{
title: “点赞数”,
dataIndex: “like_count”,
key: “like_count”,
},
{
title: “操作”,
key: “action”,
render: () => (
}/>
}/>
),
},
];
04-内容管理-全局语言本地化
使用ConfigProvider组件项目语言本地化
大致步骤:
- 入口使用 ConfigProvider 改用全局语言本地化 文档
- 内容管理移除语言设置
核心代码 :
- 全局配置 src/index.js
+import ‘moment/locale/zh-cn’;
+import locale from ‘antd/lib/locale/zh_CN’;
+import { ConfigProvider } from ‘antd’;
ReactDOM.render(
// 关联react和redux
+
+
document.getElementById(‘root’)
)
- 日期组件修改 Article/index.jsx
-import “moment/locale/zh-cn”;
-import locale from “antd/es/date-picker/locale/zh_CN”;
-
+
05-内容管理-频道数据和渲染
完成频道数据获取和渲染
大致步骤:
- 准备获取频道数据的 thunk action
- 存储获取的频道数据 readucer
- 组件第一次渲染 dispatch 分发 action
- 渲染频道
核心代码:
- 准备获取频道数据的 thunk action
actions/article.js
import { http } from ‘@/utils’
export const getChannels = () => {
return async dispatch => {
const data = await http.get(‘channels’)
dispatch({ type: ‘article/setChannels’, payload: data.channels })
}
}
actions/index.js
// 把user模块下的所有内容按需导出
export from ‘./user’
+// 把article模块下的所有内容按需导出
+export from ‘./article’
- 存储获取的频道数据 readucer
reducers/article.js
const initialState = {
// 频道
channels: []
}
const article = (state = initialState, action) => {
if (action.type === “article/setChannels”) {
return {
…state,
channels: action.payload
}
}
return state
}
export default article
reducers/index.js
import { combineReducers } from ‘redux’
import user from ‘./user’
+import article from ‘./article’
export default combineReducers({
user,
+ article,
})
- 组件第一次渲染 dispatch 分发 action
Article/index.jsx
import { useDispatch, useSelector } from “react-redux”;
import { useEffect } from “react”;
import { getChannels } from “@/store/actions”;
const Article = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getChannels());
}, [dispatch]);
// 省略…
- 渲染频道
import { useDispatch, useSelector } from “react-redux”;
const { channels } = useSelector((state) => state.article);
06-内容管理-列表数据
完成获取文章列表数据
大致步骤:
- 准备获取文章数据的 thunk action
- 存储获取的文章数据 readucer
- 组件第一次渲染 dispatch 分发 action
- 渲染列表
核心代码:
- 准备获取文章数据的 thunk action
actions/article.js
export const getArticles = (params) => {
return async dispatch => {
const data = await http.get(‘mp/articles’, { params })
dispatch({ type: ‘article/setArticles’, payload: data })
}
}
- 存储获取的文章数据 readucer
reducers/article.js
const initialState = {
// 频道
channels: [],
+ // 文章
+ results: [],
+ page: 1,
+ per_page: 10,
+ total_count: 0
}
const article = (state = initialState, action) => {
if (action.type === “article/setChannels”) {
return {
…state,
channels: action.payload
}
}
+ if (action.type === “article/setArticles”) {
+ return {
+ …state,
+ …action.payload
+ }
+ }
return state
}
export default article
- 组件第一次渲染 dispatch 分发 action
+import { getChannels, getArticles } from “@/store/actions”;
const Article = () => {
const dispatch = useDispatch();
useEffect(() => {
// 获取频道数据
dispatch(getChannels());
+ // 获取文章数据
+ dispatch(getArticles({}));
}, [dispatch]);
07-内容管理-列表渲染
完成文章列表渲染
大致步骤:
- 拿到列表渲染数据
- 阅读状态数据(不同状态文字和颜色不一样)
- 渲染自定义列
核心代码:Article/index.jsx
- 拿到列表渲染数据
+const { channels, results } = useSelector((state) => state.article);
- 阅读状态数据(不同状态文字和颜色不一样)
const statusLabel = [
{ text: “草稿”, color: “default” },
{ text: “待审核”, color: “blue” },
{ text: “审核通过”, color: “green” },
{ text: “审核拒绝”, color: “red” },
];
- 通过 colums 配置渲染列表
import defaultImg from “@/assets/error.png”;
const columns = [
{
title: “封面”,
dataIndex: “cover”,
key: “cover”,
render: (cover) => (
style={{ objectFit: “cover” }}
width={200}
height={120}
/>
),
},
{
title: “标题”,
dataIndex: “title”,
key: “title”,
},
{
title: “状态”,
dataIndex: “status”,
key: “status”,
render: (status) => {
const info = statusLabel[status];
return
},
},
{
title: “发布时间”,
dataIndex: “pubdate”,
key: “pubdate”,
},
{
title: “阅读数”,
dataIndex: “read_count”,
key: “read_count”,
},
{
title: “评论数”,
dataIndex: “comment_count”,
key: “comment_count”,
},
{
title: “点赞数”,
dataIndex: “like_count”,
key: “like_count”,
},
{
title: “操作”,
key: “action”,
render: () => (
} />
} />
),
},
];
08-内容管理-筛选功能
完成点击筛选按钮根据筛选条件查询文章列表
大致步骤:
- 绑定表单的完成事件 onFinish
- 处理表单的日期数据为后台需要参数,通过 dispatch 调用 action 传参,完成列表更新
核心代码:Article/index.jsx
- 绑定表单的完成事件 onFinish
+
+
// 改变筛选条件查询
const onFinish = (values) => {
console.log(values)
};
- 处理表单的日期数据为后台需要参数,通过 dispatch 调用 action 传参,完成列表更新
// 改变筛选条件查询
const onFinish = (values) => {
const params = {}
params.status = values.status;
params.channel_id = values.channel_id;
if (values.dateArr) {
params.begin_pubdate = values.dateArr[0].format(
“YYYY-MM-DD HH:mm:ss”
);
params.end_pubdate = values.dateArr[1].format(
“YYYY-MM-DD HH:mm:ss”
);
} else {
params.begin_pubdate = undefined;
params.end_pubdate = undefined;
}
dispatch(getArticles(params));
};
09-内容管理-分页功能
完成分页的渲染和分页功能
大致步骤:
- 拿到分页数据通过 Tabel de pagination 属性渲染分页
- 实现分页功能,支持分页页码和分页条数设置
核心代码:Article/index.jsx
- 拿到分页数据通过 Tabel de pagination 属性渲染分页
const {
channels,
results,
+ page,
+ per_page,
+ total_count
} = useSelector((state) => state.article);
- 实现分页功能,支持分页页码和分页条数设置
// 改变分页和size重新查询
const onPageChange = (page,pageSize) => {
const params = {}
params.page = page
params.per_page = pageSize
dispatch(getArticles(params));
}
问题: 分页的参数和筛选的参数是分开的,分页的时候带不上筛选的条件(BUG)
10-内容管理-关联筛选分页参数
把筛选的参数和分页的参数进行关联完成联合查询
大致步骤:
- 需要知道,怎么存储数据,不导致页面刷新。
- 声明 ref 保存参数数据
- 更改筛选参数的时候,分页默认变成第一页,分页的条数不变。
- 进行分页查询的时候,筛选条件的参数需要保留。
具体内容:
- 明白不能使用 state 来存储筛选条件
// 这个来保存参数会导致页面重新渲染,这里没有第二个参数监听渲染完毕后,且查询参数没有在页面上渲染。
setState({})
// 在这里立即去调用dispatch是拿不到最新的参数,因为需要封setState()渲染组件后才能拿到最新状态。
const ref = useRef()
// 这个ref记录的数据改变不会引起组件渲染,且可以存储数据而且是立即生效,就是一个普通的数据
// 使用场景:在组件中要记录数据,且组件每次更新能不变,这些数据不需要去渲染的。
- 声明 ref 保存参数数据
import { useEffect, useRef } from “react”;
// 请求参数
const params = useRef({
page: 1,
per_page: 20,
channel_id: undefined,
status: undefined,
begin_pubdate: undefined,
end_pubdate: undefined,
});
useEffect(() => {
dispatch(getChannels());
+ dispatch(getArticles(params.current));
}, [dispatch]);
- 更改筛选参数的时候,分页默认变成第一页,分页的条数不变。
// 改变筛选条件查询
const onFinish = (values) => {
params.current.status = values.status;
params.current.channel_id = values.channel_id;
console.log(values);
if (values.dateArr) {
params.current.begin_pubdate = values.dateArr[0].format(
“YYYY-MM-DD HH:mm:ss”
);
params.current.end_pubdate = values.dateArr[1].format(
“YYYY-MM-DD HH:mm:ss”
);
} else {
params.current.begin_pubdate = undefined;
params.current.end_pubdate = undefined;
}
params.current.page = 1
dispatch(getArticles(params.current));
};
- 进行分页查询的时候,筛选条件的参数需要保留。
// 改变分页重新查询
const onPageChange = (page,pageSize) => {
params.current.page = page
params.current.per_page = pageSize
dispatch(getArticles(params.current));
}
11-内容管理-删除文章
完成文章的删除功能
大致步骤:
- 绑定点击按钮,完成确认框弹出
- 完成删除逻辑(dispatch—->action)
核心代码:
- 绑定点击按钮,完成确认框弹出 Article/index.jsx
{
title: “操作”,
key: “action”,
render: (text, record) => (
+ } />
),
},
// 删除
const delArticleFn = id => {
Modal.confirm({
title: ‘您是否确认删除该文章?’,
cancelText: ‘取消’,
okText: ‘确认’,
onOk: () => {
console.log(id)
},
})
}
- 完成删除逻辑(dispatch—->action)
actions/article.js
export const delArticle = id => {
return async dispatch => {
await request.delete(‘mp/articles/‘ + id)
}
}
Article/index.jsx
// 删除
const delArticleFn = id => {
Modal.confirm({
title: ‘您是否确认删除该文章?’,
cancelText: ‘取消’,
okText: ‘确认’,
onOk: async () => {
await dispatch(delArticle(id))
await dispatch(getArticles(params.current));
message.success(‘删除成功’)
},
})
}
12-内容管理-编辑跳转
完成点击按钮跳转到编辑文章页面
大致步骤:
- 绑定事件使用history跳转
核心代码: