【系列】使用ThinkPHP6+React+Antd搭建博客系统(十七)
前言
前面我们已经将博客搭建完成,已经满足了平时对于文章创建和编辑工作。一开始时,我感觉富文本编辑器比较符合我们的使用习惯,但是今天,当我使用 Markdown
做笔记的时候,发现 Markdown
语法更简洁,书写更高效,真是后知后觉。
另外,对于页面中代码的支持,利用 Markdown
高亮插件,可以很方便的进行标记(真的很方便,只能说真香),更符合沉浸式写作。
关于富文本编辑器组件 braft-editor
使用,参考之前的文章:
富文本编辑器 braft-editor
也是支持代码高亮的
参考链接:使用代码高亮扩展
好了,本篇教程将为我们的博客支持 Markdown
编写文章。
第一步 选择React Markdown插件
如果你从Google上搜索 React Markdown
,排名靠前的是 react-markdown
这个插件。但是,这个插件只是对Markdown语法的解析,并不是Markdown的编辑器,而且我也没有找到 react-markdown
将 Markdown
字符串转成 HTML 字符串的API。 而我们需要的是一个 Markdown
编辑器和 Markdown
语法解析器。
这里我们选择 for-editor
作为 Markdown
编辑器,使用 marked
将 Markdown
转义为 HTML
。下面开始代码编写
npm install marked
npm install for-editor
npm install highlight.js // 代码高亮
这里说明一下,
for-editor
编辑器中需要使用Markdown的语法,并不会像富文本编辑器一样所见即所得
,如果大家需要实时转义的编辑器可以自行寻找。
这里是关于Markdown语法说明:Markdown基本语法
第二步 后台Markdown编辑页面
- 新建路由,路由文件位置
src/router/index.js
{
path: '/article/md-edit/:id?',
name: 'MarkDown编辑',
component: () => (<MdEdit />),
isFull: true,
hidden: true, // 隐藏
}
- 修改 ArticleList 页面
import { Link, useHistory } from "react-router-dom";
const history = useHistory();
// 这里我们通过type,区分是进入Markdown还是富文本编辑页面
function handleCreateClick(type) {
switch(type) {
case 'html':
history.push("/article/edit");
break
default:
history.push("/article/md-edit");
}
}
- 编写 MdEdit 页面
MdEdit
页面与 Edit
页面基本是一样的,只是改变一下编辑器插件。
关于
Edit
页面与代码参考,链接:后端博客管理
页面示例,仅供参考
下面是部分代码
import { marked } from 'marked'
import Editor from 'for-editor'
import hljs from "highlight.js";
// 配置marked
let renderer = new marked.Renderer();
// 配置链接,点击链接时,打开新的浏览器窗口
renderer.link = function( href, title, text ) {
return `<a target="_blank" href="${href}" title="${title}">${text}</a>`
}
marked.setOptions({
renderer: renderer,
highlight: function(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
},
langPrefix: 'hljs language-', // highlight.js css expects a top-level 'hljs' class.
pedantic: false,
gfm: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
});
上面针对
link
标签进行了单独设置,点击链接时,打开新的浏览器窗口
参考配置页面:Github Issues
// 保存Markdown文本内容
const [mdContent, setMdContent] = useState('')
function handleEditorChange(value) {
setMdContent(value)
}
<Editor value={mdContent} onChange={handleEditorChange} />
// 保存文章内容,这是使用Antd的Form组件,保存时进行表单验证,提交必要的文章标题、作者等信息
form.validateFields().then(values => {
let url = articleAddUrl;
if(id) {
url = articleEditUrl;
}
post(url, {
id,
status,
is_markdown: 1,
md_content: mdContent, // 原始Markdown内容
content: marked.parse(mdContent), // 转义为HTML内容,方便前端渲染
...values
});
})
我们可以实现 Markdown
文章内容的编写了,可以增加一个预览效果的功能按钮,点击预览,弹层看到文章的展示,下面是部分代码
const [previewVisible, setPreviewVisible] = useState(false);
const [previewHTMLContent, setPreviewHTMLContent] = useState('')
// 预览方法
function handlePreviewClick() {
let html = marked.parse(mdContent)
setPreviewVisible(true)
setPreviewHTMLContent(html)
}
// 取消预览
function handlePreviewHTMLCancel() {
setPreviewVisible(false)
setPreviewHTMLContent('')
}
// 预览按钮
<Button
shape="round"
size="large"
onClick={handlePreviewClick}>预览</Button>
// 预览组件
<HTMLPreviewModal
visible={previewVisible}
content={previewHTMLContent}
handleOk={handlePreviewHTMLCancel}
handleCancel={handlePreviewHTMLCancel} />
// 预览组件
import { Modal } from 'antd'
import 'highlight.js/styles/base16/onedark.css' // 引入渲染的主题样式
function HTMLPreviewModal({ visible, content, handleOk, handleCancel }) {
return (
<Modal
title="Markdown内容预览"
width="60%"
visible={visible}
onOk={handleOk}
onCancel={handleCancel}>
<div className="site-html-preview-content" dangerouslySetInnerHTML={{ __html:content }}></div>
</Modal>
)
}
export default HTMLPreviewModal;
提示:这里的主题样式文件,也需要加到前端的文章详情页CSS文件中,否则无法呈现显示效果
第三步 修改数据库表结构
之前设计的表结构,只有一个 content
内容字段。
从上面代码可以看出,我们还需要一个 md_content
字段,专门用来存放 Markdown
的内容(因为 content
存放的是纯HTML字符串,在编辑 Markdown
文章时,再将 content
转义回 Markdown
格式并不方便)。所以这里我增加了两个字段 is_markdown
和 md_content
(is_markdown
标识是 Markdown
内容,也可以不加,只判断 md_content
字段是否为空即可)。
当我们后台文章编辑完成后,转义成 HTML
内容,保存到 content
字段中,发送给服务器。
第四步 修改前端页面展示
前端页面展示时,如果是 Markdown
内容,我们单独多添加一下 class
,这样方便CSS样式的修改
<!-- 这里的语法使用的ThinkPHP中的模版语法,请结合自己实际情况进行页面渲染 -->
<div class="article-detail__container {if $article.is_markdown == 1}site-markdown-container{/if}">
<div class="article-detail__content">
{$article.content|raw}
</div>
</div>
补充
highlight.js
官方demo中有很多代码主题,选择自己喜欢的,我这里选择的是 Base16/Onedark
,Demo链接
最后
这样我们就可以愉快的编写文章了,不得不说,Markdown
编写效率可能更高一点,哈哈。后面我们还可以支持一下图片便捷上传功能等。