一,背景

     近几天工作比较轻松吧,打算把之前没有完成的博客后台管理系统的发布博客功能实现,这就需要一个基于react的markdown编辑器

    之前的博客实现是使用vue实现的,后台管理想使用react,对于vue的markdown编辑器还是非常多而且健全的,但基于react的markdown编辑器,,说实话,少而功能不全,找了很多,也试了很多,总体来讲体验不好。不过,最后还是找到了——

braft-editor。

效果图:

二,介绍(文档

安装和使用

安装

使用npm或者yarn来将本编辑器加入到你的项目中:

# 使用npm安装
npm install braft-editor --save

# 使用yarn安装
yarn add braft-editor

注意:对于传统的scrpt标签引入方式,本项目暂未进行充分测试

使用

 

编辑器支持valueonChange属性,这类似于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属性,因此你也可以将本编辑器作为一个非受控组件来使用。


编辑器的内容格式

对于上文提到的valuedefaultValue属性,均需要传入一个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 富文本中的最合心意的了,当然坑还是有的,有什么建议,欢迎一起讨论。

 

Logo

前往低代码交流专区

更多推荐