image.png

01-发布文章-页面结构

完成页面基本结构搭建
大致步骤:

  • 使用 Card 组件搭建布局容器和面包屑
  • 使用 Form 组件表单
  • 准备 标题选项 和 频道选项

核心代码:
Artilce/index.jsx
import { Card, Breadcrumb, Form, Select, Button, Input } from ‘antd’
import { getChannels } from “@/store/actions/article”;
import { useDispatch, useSelector } from “react-redux”;
import { Link } from ‘react-router-dom’
import styles from “./index.module.scss”;
const Publish = () => {
// 频道数据
const channels = useSelector((state) => state.article.channels);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getChannels());
}, [dispatch]);

return (


title={


首页


内容管理

发布文章

}
>

label=”文章标题:”
name=”title”
>


label=”所属频道:”
name=”channel_id”
>










)
}
Artilce/index.module.scss
.root {
padding: 24px;
:global {
.ql-editor {
min-height: 200px;
}
}
}

02-发布文章-频道组件封装

封装频道组件逻辑与UI,且在Form组件中使用
大致步骤:

  • 提取频道组件自身功能
  • 实现value赋值,onChange改值,也就是父子通讯

具体代码:

  • 封装 components/Channel.jsx

// 需求:
// 1. 实现频道本身的功能,获取频道数据,展示频道选项,可以选择频道
// 2. 实现传入频道ID显示对应频道,自己更改频道的时候需要把更改的频道ID传给父组件
// 3. 而且现在是在form表单上使用,要符合form表单的要求,value赋值,onChange改值
import { useDispatch, useSelector } from “react-redux”;
import { useEffect } from “react”;
import { getChannels } from “@/store/actions”;
import { Select } from “antd”;

const Channel = ({ width, value, onChange }) => {
// 频道相关逻辑
const dispatch = useDispatch();
useEffect(() => {
dispatch(getChannels());
}, [dispatch]);
const { channels } = useSelector((state) => state.article);
return (
value={value}
onChange={(e) => onChange(e)}
placeholder=”请选择所属频道”
style={width ? { width } : null}
>
{channels.map((item) => (

{item.name}

))}

);
};

export default Channel;

  • 使用 Article/index.jsx



  • 使用 Publish/index.jsx



03-发布文章-处理封面

完成封面类型切换,完成封面图上传。
大致步骤:

  • 完成封面类型渲染和切换
  • 完成封图上传,根据封面类型限制上传的图片张数
  • 切换封面的时候重置数据

具体代码:Artilce/index.jsx
import {
Radio,
Upload,
} from “antd”;
import { useState } from “react”;

  1. 完成封面类型渲染和切换

const [type, setType] = useState(1);
const onTypeChange = (e) => {
setType(e.target.value);
};

{/ 一个FormItem只能有一个元素 /}


单图
三图
无图


{/ 这个位置放Upload组件 /}

  1. 完成封图上传,根据封面类型限制上传的图片张数

const [fileList, setFileList] = useState([]);
const onUploadChange = ({ fileList }) => {
setFileList(fileList);
};
{type > 0 ? (


name=”image”
listType=”picture-card”
action=”http://geek.itheima.net/v1_0/upload
fileList={fileList}
onPreview={() => {}}
onChange={onUploadChange}
>
{fileList.length < type ? (


Upload


) : null}


) : null}

  1. 切换封面的时候重置数据

const onTypeChange = (e) => {
setType(e.target.value);
+ setFileList([]);
};

04-发布文章-富文本编辑器

使用react-quill富文本编辑器完成文章内容选项
大致步骤:

  • 安装导入 react-quill 组件
  • 使用 react-quill 组件
  • 处理默认值问题
  • 处理宽度

核心代码:

  1. 安装导入 react-quill 组件

npm i react-quill
# or
yarn add react-quill
+import ReactQuill from “react-quill”;
+import “react-quill/dist/quill.snow.css”;
import styles from “./index.module.scss”;

  1. 使用 react-quill 组件

label=”文章内容:”
name=”content”
initialValue=””
>

  1. 处理默认值问题

label=”文章内容:”
name=”content”
+ initialValue=””
>

  1. 处理宽度

label=”文章内容:”
name=”content”
+ wrapperCol={{ span: 16 }}
initialValue=””
>

05-发布文章-添加校验

给标题,频道,内容必填校验,提交表单校验封面类和图片张数
大致步骤:

  • 标题,频道,内容必填校验
  • 提交表单校验封面类和图片张数

核心代码:

  1. 标题,频道,内容必填校验

label=”文章标题:”
name=”title”
+ rules={[{ required: true, message: “请输入文章标题” }]}
>
label=”所属频道:”
name=”channel_id”
+ rules={[{ required: true, message: “请选择所属频道” }]}
>
label=”文章内容:”
name=”content”
wrapperCol={{ span: 16 }}
+ rules={[{ required: true, message: “请输入文章内容” }]}
initialValue=””
>

  1. 提交表单校验封面类和图片张数
  1. 点击发布文章,需要重置数据

useEffect(() => {
const setFormData = async () => {
if (params.id) {
const { title, cover, content, channel_id } = await dispatch(
getArticle(params.id)
);
form.setFieldsValue({ title, content, channel_id });
setType(cover.type);
setFileList(cover.images.map((item) => ({ url: item })));
+ } else {
+ setType(1);
+ setFileList([]);
+ form.resetFields();
+ }
};
setFormData();
+ }, [dispatch, form, params]);

  1. 提交修改

const onFinish = async (values) => {
if (type !== fileList.length) {
return message.warning(“请按照选择的封面类型上传图片”);
}
const data = {
…values,
cover: {
type,
+ images: fileList.map((item) => {
+ return item?.response?.data?.url || item.url;
+ }),
},
};
+ if (params.id) {
+ // 编辑
+ data.id = params.id
+ await dispatch(editArticle(data));
+ } else {
// 添加
await dispatch(addArticle(data));
+ }
history.push(“/article”);
};

08-发布文章-存入草稿

实现存入草稿功能
大致步骤:

  • 改造 onFinish 函数支持,存入草稿调用
  • 添加存入草稿按钮,添加处理函数

核心代码:

  • 改造 onFinish 函数支持,存入草稿调用
  • const onFinish = async (values, draft = false) => {
    if (type !== fileList.length) {
    return message.warning(“请按照选择的封面类型上传图片”);
    }
    const data = {
    …values,
    cover: {
    type,
    images: fileList.map((item) => {
    return item?.response?.data?.url || item.url;
    }),
    },
    };
    if (params.id) {
    // 编辑
    data.id = params.id
    + await dispatch(editArticle(data, draft));
    } else {
    // 添加
    + await dispatch(addArticle(data, draft));
    }
    + message.success(‘保存成功’)
    history.push(“/article”);
    };
  • 添加存入草稿按钮,添加处理函数



+

const saveDarft = async () => {
try {
const values = await form.validateFields()
onFinish(values, true)
}catch(e){}
}
2021/12/30 23:22:54