因为 编辑文章是编辑不同的文章,所以这里需要 使用动态 路由
首先新建 pages/editor/[id].tsx 和 index.module.scss
编辑文章 首先 需要 把 当前的文章详情 回显到页面上
这里通过 url 获取 当前 文章的 id
然后通过ssr渲染的方式进行渲染
根据 文章 id 和 关联的 用户表,链接 文章的 数据表,查询出来 属于 当前用户发布的这篇文章
最后将 查询出来的 文章详情返回
export async function getServerSideProps({ params }: any) {
const articleId = params?.id;
const db = await prepareConnection();
const articleRepo = db.getRepository(Article);
const article = await articleRepo.findOne({
where: {
id: articleId,
},
relations: ['user'],
});
return {
props: {
article: JSON.parse(JSON.stringify(article)),
},
};
}
在react客户端组件中,通过props获取article数据
将 文章标题,文章内容通过state来控制,初始值是props获取的数据
const [title, setTitle] = useState(article?.title || '');
const [content, setContent] = useState(article?.content || '');
通过 useRouter hooks 获取 文章Id
const { push, query } = useRouter();
const articleId = Number(query?.id)
将获取的文章数据渲染出来
return (
<div className={styles.container}>
<div className={styles.operation}>
<Input
className={styles.title}
placeholder="请输入文章标题"
value={title}
onChange={handleTitleChange}
/>
<Select
className={styles.tag}
mode="multiple"
allowClear
placeholder="请选择标签"
onChange={handleSelectTag}
>{allTags?.map((tag: any) => (
<Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
))}</Select>
<Button
className={styles.button}
type="primary"
onClick={handlePublish}
>
发布
</Button>
</div>
<MDEditor value={content} height={1080} onChange={handleContentChange} />
</div>
);
修改标题,通过state控制
const handleTitleChange = (event: ChangeEvent<HTMLInputElement>) => {
setTitle(event?.target?.value);
};
修改 文章内容的时候,也是通过state控制
const handleContentChange = (content: any) => {
setContent(content);
};
这里 新增一个 获取所有标签的接口
首先 调用 标签接口,将标签数据存到state中
useEffect(() => {
request.get('/api/tag/get').then((res: any) => {
if (res?.code === 0) {
setAllTags(res?.data?.allTags || [])
}
})
}, []);
接下来编写下 获取标签的接口
新建 pages/api/tag/get.ts
1.首先通过session获取当前用户信息
const session: ISession = req.session;
const { userId = 0 } = session;
2.链接 标签的数据表
const db = await prepareConnection();
const tagRepo = db.getRepository(Tag);
3.根据当前关联的用户表,查询出来所有标签
const allTags = await tagRepo.find({
relations: ['users'],
});
4.根据用户id查询出来 当前用户关注的标签
const followTags = await tagRepo.find({
relations: ['users'],
where: (qb: any) => {
qb.where('user_id = :id', {
id: Number(userId),
});
},
});
5.最后将所有的标签 和 当前用户 关注的 标签 返回
res?.status(200)?.json({
code: 0,
msg: '',
data: {
followTags,
allTags,
},
});
6.在客户端 拿到 所有标签数据后渲染出来
<Select
className={styles.tag}
mode="multiple"
allowClear
placeholder="请选择标签"
onChange={handleSelectTag}
>{allTags?.map((tag: any) => (
<Select.Option key={tag?.id} value={tag?.id}>{tag?.title}</Select.Option>
))}</Select>
接着开始写 更新 文章的逻辑
1、当点击更新的时候,首先判断一下 是否 输入了标题,如果没有输入标题,则提示用户输入标题
if (!title) {
message.warning('请输入文章标题');
return ;
}
2、然后传参数调用更新文章的接口
3、传的参数包括 文章id、标题、内容、标签
4、当调用更新文章接口成功的时候提示更新文章成功并跳到当前文章
5、如果失败,则提示发布失败
request.post('/api/article/update', {
id: articleId,
title,
content,
tagIds
}).then((res: any) => {
if (res?.code === 0) {
articleId ? push(`/article/${articleId}`) : push('/');
message.success('更新成功');
} else {
message.error(res?.msg || '发布失败');
}
})
6、接着编写 更新文章的接口,新建 pages/api/article/update.ts
7、通过body获取 前端传过来的数据
const { title = '', content = '', id = 0, tagIds = [] } = req.body;
8、链接文章和标签的数据库
const articleRepo = db.getRepository(Article);
const tagRepo = db.getRepository(Tag);
9、根据文章的id,关联用户表和标签表,查询出来当前文章
const article = await articleRepo.findOne({
where: {
id,
},
relations: ['user', 'tags'],
});
10、判断查询出来的article是否存在,如果不存在,则提示文章不存在
res.status(200).json({ ...EXCEPTION_ARTICLE.NOT_FOUND });
11、如果存在,则将传过来的文章数据 覆盖之前的数据,如果保存成功,则提示成功,否则提示失败
if (article) {
article.title = title;
article.content = content;
article.update_time = new Date();
article.tags = newTags;
const resArticle = await articleRepo.save(article);
if (resArticle) {
res.status(200).json({ data: resArticle, code: 0, msg: '更新成功' });
} else {
res.status(200).json({ ...EXCEPTION_ARTICLE.UPDATE_FAILED });
}
}
12、这里需要根据传过来的标签id,查询出来所有标签,然后将标签数量加1
const tags = await tagRepo.find({
where: tagIds?.map((tagId: number) => ({ id: tagId })),
});
const newTags = tags?.map((tag) => {
tag.article_count = tag.article_count + 1;
return tag;
});
13、最后记得将 需要的 第三方库引入进来
import { NextApiRequest, NextApiResponse } from 'next';
import { withIronSessionApiRoute } from 'iron-session/next';
import { ironOptions } from 'config/index';
import { prepareConnection } from 'db/index';
import { Article, Tag } from 'db/entity/index';
import { EXCEPTION_ARTICLE } from 'pages/api/config/codes';
这样就完成了编辑文章的前后端开发。