基于react 的markdown编辑器
一,背景近几天工作比较轻松吧,打算把之前没有完成的博客后台管理系统的发布博客功能实现,这就需要一个基于react的markdown编辑器。之前的博客实现是使用vue实现的,后台管理想使用react,对于vue的markdown编辑器还是非常多而且健全的,但基于react的markdown编辑器,,说实话,少而功能不全,找了很多,也试了很多,总体来讲体验不好。不过,最后还是...
一,背景
近几天工作比较轻松吧,打算把之前没有完成的博客后台管理系统的发布博客功能实现,这就需要一个基于react的markdown编辑器。
之前的博客实现是使用vue实现的,后台管理想使用react,对于vue的markdown编辑器还是非常多而且健全的,但基于react的markdown编辑器,,说实话,少而功能不全,找了很多,也试了很多,总体来讲体验不好。不过,最后还是找到了——
braft-editor。
效果图:
二,介绍(文档)
安装和使用
安装
使用npm或者yarn来将本编辑器加入到你的项目中:
# 使用npm安装
npm install braft-editor --save
# 使用yarn安装
yarn add braft-editor
注意:对于传统的scrpt标签引入方式,本项目暂未进行充分测试
使用
编辑器支持value和onChange属性,这类似于React中原生的input组件。通常情况下,可以用典型的受控组件的形式来使用本编辑器:
import React from 'react'
// 引入编辑器组件
import BraftEditor from 'braft-editor'
// 引入编辑器样式
import 'braft-editor/dist/index.css'
export default class EditorDemo extends React.Component {
state = {
// 创建一个空的editorState作为初始值
editorState: BraftEditor.createEditorState(null)
}
async componentDidMount () {
// 假设此处从服务端获取html格式的编辑器内容
const htmlContent = await fetchEditorContent()
// 使用BraftEditor.createEditorState将html字符串转换为编辑器需要的editorStat
this.setState({
editorState: BraftEditor.createEditorState(htmlContent)
})
}
submitContent = async () => {
// 在编辑器获得焦点时按下ctrl+s会执行此方法
// 编辑器内容提交到服务端之前,可直接调用editorState.toHTML()来获取HTML格式的内容
const htmlContent = this.state.editorState.toHTML()
const result = await saveEditorContent(htmlContent)
}
handleEditorChange = (editorState) => {
this.setState({ editorState })
}
render () {
const { editorState } = this.state
return (
<div className="my-component">
<BraftEditor
value={editorState}
onChange={this.handleEditorChange}
onSave={this.submitContent}
/>
</div>
)
}
}
当然本编辑器也支持defaultValue属性,因此你也可以将本编辑器作为一个非受控组件来使用。
编辑器的内容格式
对于上文提到的value和defaultValue属性,均需要传入一个editorState对象,这一点类似于Ant Design中的日期选择器组件,它使用moment对象作为数据格式。
关于editorState的具体介绍,请参见:https://draftjs.org/docs/api-reference-editor-state.html 。
在实际项目中,editorState对象无法用于展示也无法用于持久化存储,需要将其转换为html字符串来进行展示,用于持久化时则建议转换成raw格式。
raw格式是一种可以用于无损持久化的数据格式,形式上是一段JSON,因此可以用字符串形式存储,推荐使用这种格式来用于数据持久化。下面是一段raw格式的数据示例:
{
"blocks": [{
"key": "9hu83",
"text": "Hello World!",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [{
"offset": 6,
"length": 5,
"style": "BOLD"
},
{
"offset": 6,
"length": 5,
"style": "COLOR-F32784"
}],
"entityRanges": [],
"data": {}
}],
"entityMap": {}
}
虽然html字符串也可以用于持久化存储,但是对于比较复杂的富文本内容,在反复编辑的过程中,可能会存在格式丢失的情况,比较标准的做法是在数据库中同时存储raw字符串和html字符串,分别用于再次编辑和前台展示。
可以使用BraftEditor.createEditorState方法来将raw或者html格式的数据转换成editorState数据:
// 引入EditorState
import BraftEditor from 'braft-editor'
// 将raw格式的数据转换成editorState
const rawString = `{"blocks":[{"key":"9hu83","text":"Hello World!","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":6,"length":5,"style":"BOLD"},{"offset":6,"length":5,"style":"COLOR-F32784"}],"entityRanges":[],"data":{}}],"entityMap":{}}`
const editorState = BraftEditor.createEditorState(rawString)
// 将html字符串转换成editorState
const htmlString = `<p>Hello <b>World!</b></p>`
const editorState2 = BraftEditor.createEditorState(htmlString)
BraftEditor.createEditorState方法内部做了诸多适配处理,你可以直接传入raw字符串、raw JSON和html字符串,只要传入的内容有效,都能获得对应的editorState数据。
将editorState数据转换成raw或者html则更方便:
// 将editorState数据转换成RAW字符串
const rawString = editorState.toRAW()
// editorState.toRAW()方法接收一个布尔值参数,用于决定是否返回RAW JSON对象,默认是false
const rawJSON = editorState.toRAW(true)
// 将editorState数据转换成html字符串
const htmlString = editorState.toHTML()
美化输出内容
编辑器输出的HTML字符串仅包含文本内联样式和少量的布局样式,例如图片的左右浮动等。对于引语块(blockquote)、代码块(code block)等内容,一般情况下需要自行美化。
从v2.2.7开始,编辑器新增了一个css样板文件用于进行输出内容的基本美化功能,能够尽量做到输出内容的展示效果接近编辑器编辑时的效果。使用方法如下:
// 在展示页面引入css样板文件
import 'braft-editor/dist/output.css'
// 给用于展示HTML内容的容器加上特定的className
<div className="braft-output-content" dangerouslySetInnerHTML={{__html: outputContent}}></div>
注意事项
因为编辑器的选区状态(包括所选内容和光标位置等),都是包含在editorState对象中的,如果将editorState转换成html,再将html转换成editorState,得到的是一个新的editorState,它不包含之前的选区状态,所以类似于下面的这种写法是错误的!除了会导致光标回跳,更可能会导致无限onChange!
// 错误示范!
<BraftEditor
value={BraftEditor.createEditorState(this.state.value)}
onChange={(editorState) => this.setState({ value: editorState.toHTML() })}
>
三,总结
总体来说,使用还是比较简单的,不管怎么说,这个算是我近期遇到的react 富文本中的最合心意的了,当然坑还是有的,有什么建议,欢迎一起讨论。
更多推荐
所有评论(0)