前情提要-Layout模块完成
发布文章模块
- 4、发布文章模块
-
- [4-1 实现基础文章发布](#4-1 实现基础文章发布)
- [4-2 上传封面实现](#4-2 上传封面实现)
- [4-3 切换图片Type](#4-3 切换图片Type)
- [4-4 控制最大上传图片数量](#4-4 控制最大上传图片数量)
- [4-5 发布带封面的文章](#4-5 发布带封面的文章)
- [4-6 暂存图片列表实现](#4-6 暂存图片列表实现)
4、发布文章模块
4-1 实现基础文章发布
创建基础结构

pages/Publish/index.jsx
jsx
import {
Card,
Breadcrumb,
Form,
Button,
Radio,
Input,
Upload,
Space,
Select
} from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { Link } from 'react-router-dom'
import './index.scss'
const { Option } = Select
const Publish = () => {
return (
<div className="publish">
<Card
title={
<Breadcrumb items={[
{ title: <Link to={'/'}>首页</Link> },
{ title: '发布文章' },
]}
/>
}
>
<Form
labelCol={{ span: 4 }}
wrapperCol={{ span: 16 }}
initialValues={{ type: 1 }}
>
<Form.Item
label="标题"
name="title"
rules={[{ required: true, message: '请输入文章标题' }]}
>
<Input placeholder="请输入文章标题" style={{ width: 400 }} />
</Form.Item>
<Form.Item
label="频道"
name="channel_id"
rules={[{ required: true, message: '请选择文章频道' }]}
>
<Select placeholder="请选择文章频道" style={{ width: 400 }}>
<Option value={0}>推荐</Option>
</Select>
</Form.Item>
<Form.Item
label="内容"
name="content"
rules={[{ required: true, message: '请输入文章内容' }]}
></Form.Item>
<Form.Item wrapperCol={{ offset: 4 }}>
<Space>
<Button size="large" type="primary" htmlType="submit">
发布文章
</Button>
</Space>
</Form.Item>
</Form>
</Card>
</div>
)
}
export default Publish
pages/Publish/index.scss
css
.publish {
position: relative;
}
.ant-upload-list {
.ant-upload-list-picture-card-container,
.ant-upload-select {
width: 146px;
height: 146px;
}
}
提交-17发布文章-基础结构搭建

准备富文本编辑器
实现步骤
- 安装富文本编辑器
- 导入富文本编辑器组件以及样式文件
- 渲染富文本编辑器组件
- 调整富文本编辑器的样式

代码落地
1-安装 react-quill
bash
npm i react-quill@2.0.0-beta.2 --legacy-peer-deps
2-导入资源渲染组件
bash
import ReactQuill from 'react-quill'
import 'react-quill/dist/quill.snow.css'
<ReactQuill
className="publish-quill"
theme="snow"
placeholder="请输入文章内容"
/>
pages/Publish/index.jsx

css
.publish-quill {
.ql-editor {
min-height: 300px;
}
}
pages/Publish/index.scss

提交-18发布文章-接入富文本编辑器

频道数据获取
实现步骤
- 使用useState初始化数据和修改数据的方法
- 在useEffect中调用接口并保存数据
- 使用数据渲染对应模版

apis/article.jsx
jsx
// 封装文章相关的所有请求
import { request } from "@/utils"
// 获取所有频道
export function getChannelAPI(formData) {
// axios规范写法
return request({
url: '/channels',
method: 'GET',
})
}
pages/Publish/index.jsx

提交-19发布文章-频道列表的获取渲染

发布文章

测试

提交-20发布文章-基础文章发布

4-2 上传封面实现

准备上传结构
放在内容的上面,频道的下面
jsx
<Form.Item label="封面">
<Form.Item name="type">
<Radio.Group>
<Radio value={1}>单图</Radio>
<Radio value={3}>三图</Radio>
<Radio value={0}>无图</Radio>
</Radio.Group>
</Form.Item>
<Upload
listType="picture-card"
showUploadList
>
<div style={{ marginTop: 8 }}>
<PlusOutlined />
</div>
</Upload>
</Form.Item>
实现现基础上传
实现步骤
- 为 Upload 组件添加
action 属性,配置封面图片上传接口地址 - 为 Upload组件添加
name属性, 接口要求的字段名 - 为 Upload 添加
onChange 属性,在事件中拿到当前图片数据,并存储到React状态中
代码实现

测试



注意
上传的图片不能太大,不然会返回500,选一张图片大小小于1MB的上传

我用apifox测试半天,以为是接口坏了,后面发现是上传的图片文件太大了
提交-21封面的基础上传

4-3 切换图片Type
实现步骤
- 点击单选框时拿到当前的类型value
- 根据value控制上传组件的显示(大于零时才显示)

提交-22图片封面类型的切换交互实现

4-4 控制最大上传图片数量
实现步骤
- 通过 maxCount 属性限制图片的上传图片数量


提交-23限制图片最大上传数量

4-5 发布带封面的文章
校验图片类型和数量是否吻合

处理图片列表格式为接口格式
后端发布文章接口要求的images格式

实际获取的imageList格式


测试

4-6 暂存图片列表实现
业务描述
如果当前为三图模式,已经完成了上传,选择单图只显示一张,再切换到三图继续显示三张,该如何实现?
实现思路
在上传完毕之后通过ref存储所有图片,需要几张就显示几张,其实也就是把ref当仓库,用多少拿多少
实现步骤
- 通过useRef创建一个暂存仓库,在上传完毕图片的时候把图片列表存入
- 如果是单图模式,就从仓库里取第一张图,以数组的形式存入fileList
- 如果是三图模式,就把仓库里所有的图片,以数组的形式存入fileList
fileList :已经上传的文件列表(受控),Upload 组件会根据 fileList 自动渲染已选择 / 已上传的文件
代码实现

注意:需要给Upload组件添加fileList属性,达成受控的目的

fileList 是 Upload 组件的「状态核心」
- 类型必须是数组:空列表用 [],单个文件用 [文件对象];
- 数组元素是文件对象:包含 uid、name、status 等关键属性;
- 通过 onChange 实现受控:组件状态变化后,通过 setFileList 更新 fileList,形成闭环。
提交-24携带封面图发布文章
