React富文本插件:基于draft-js 的 react-draft-wysiwyg 的使用(2019.11.29)

一、开始

安装以下依赖:

npm i draft-js react-draft-wysiwyg draftjs-to-html html-to-draftjs

引入:

// 核心
import { EditorState, convertToRaw, ContentState } from 'draft-js'
import { Editor } from 'react-draft-wysiwyg'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
// draft 转换为 html
import draftToHtml from 'draftjs-to-html'
// html 转换为 draft
import htmlToDraft from 'html-to-draftjs'

二、创建一个组件

export default class BraftEditors extends React.Component {

    constructor(props) {
        super(props)
        this.state = {
            // 创建一个空富文本
            editorState: EditorState.createEmpty()
        }
    }

    componentDidMount() {
        // 如果从后台读取接口存储的有值,读取过来转换为富文本格式默认显示
        if (this.props.htmlContent) {
            this.toDraft(this.props.htmlContent)
        }
    }

    onEditorStateChange = (editorState) => {
        this.toHtml(editorState)

        this.setState({
            editorState
        })
    }

    editorChange = value => {
        console.log(value)
    }

    // 转换为 html

    toHtml = value => {
        let templateContent = draftToHtml(convertToRaw(value.getCurrentContent()))
  
        if (this.props.getHtml) {
            // 输出已经编辑好的html
            this.props.getHtml(templateContent)
        }

    }

    // 转换为 Draft

    toDraft = value => {
        const blocksFromHtml = htmlToDraft(value);
        const { contentBlocks, entityMap } = blocksFromHtml;
        const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
        const editorState = EditorState.createWithContent(contentState);
        console.log(editorState)
        this.setState({
            editorState
        })
    }

    imgFileupOnChange = (files) => {
        // 返回值 files 就是上传的文件,控件会默认 Promise 返回,否则无法抓到返回的已上传图片链接
        return new Promise(
            (resolve, rejects) => {
                // 使用 form 表单的形式进行配置,具体参数根据接口来
                let formData = new FormData()

                formData.append('File', files)
                formData.append('FileType', 'Thumbnail')
                formData.append('IsLogin', true)
                formData.append('Description', '')

                new Ajax({
                    // 这里是配置自己的图片上传链接
                    url: `/api/file/upload`,
                    method: 'post',
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                    data: formData

                })
                    .start()
                    .then(res => (res = res.data))
                    .then(res => {
                        if (res.Status === 0) {

                            // Message.success('上传成功!')
                            resolve({ data: { link: res.Result } })
                        } else {
                            // Message.fail('上传失败!')

                        }
                    })
            }
        )


    }

    render() {
        const { editorState } = this.state
        const setToolbar = {
            colorPicker: {
                // 图标可以自定义,如果使用默认就注释掉
                // icon: 'https://-------',
                className: undefined,
                component: undefined,
                popupClassName: undefined,
                // 图片选项卡自定义
                colors: ['rgb(97,189,109)', 'rgb(26,188,156)', 'rgb(84,172,210)', 'rgb(44,130,201)',
                    'rgb(147,101,184)', 'rgb(71,85,119)', 'rgb(204,204,204)', 'rgb(65,168,95)', 'rgb(0,168,133)',
                    'rgb(61,142,185)', 'rgb(41,105,176)', 'rgb(85,57,130)', 'rgb(40,50,78)', 'rgb(0,0,0)',
                    'rgb(247,218,100)', 'rgb(251,160,38)', 'rgb(235,107,86)', 'rgb(226,80,65)', 'rgb(163,143,132)',
                    'rgb(239,239,239)', 'rgb(255,255,255)', 'rgb(250,197,28)', 'rgb(243,121,52)', 'rgb(209,72,65)',
                    'rgb(184,49,47)', 'rgb(124,112,107)', 'rgb(209,213,216)', 'rgb(0,0,0)'],
            },
            image: {
                // icon: image,
                className: undefined,
                component: undefined,
                popupClassName: undefined,
                urlEnabled: true,
                uploadEnabled: true,
                alignmentEnabled: true,
                uploadCallback: this.imgFileupOnChange,
                previewImage: true,
                inputAccept: 'image/gif,image/jpeg,image/jpg,image/png',
                alt: { present: false, mandatory: false },
                // 富文本中默认的图片尺寸,或写入到生成img标签的行间样式
                defaultSize: {
                    height: 'auto',
                    width: 'auto',
                },
            },
        }
        return (
            <div className="editor-wrap">
                <Editor
                    editorState={editorState}
                    wrapperClassName="contract-template-add-wrapper"
                    editorClassName="contract-template-editor"
                    // toolbarClassName="toolbarClassName"
                    // wrapperClassName="wrapperClassName"
                    // editorClassName="editorClassName"
                    onEditorStateChange={this.onEditorStateChange}
                    onChange={this.editorChange}
                    toolbar={setToolbar}
                />
            </div>

        )
    }
}


BraftEditors.propTypes = {
    htmlContent: PropTypes.string,
    getHtml: PropTypes.func
}

三、各函数、配置功能

onEditorStateChange 用于检测文本框中的值变化,然后再赋值给组件
editorChange 可忽略,类输入框检测变化,暂未使用
toolbar 这里边是自定义配置项,类似于图片上传和颜色选择配置都可以在这里斌完成,实例中列出了两种配置
imgFileupOnChange 上传图片配置,其中返回参数一定是固定的格式:

{ data: { link: res.Result } }

否则无法预览

其它函数请看代码注释,其它详细配置请参考官网:

https://jpuri.github.io/react-draft-wysiwyg/#/docs

四、删除一些不想留的配置项

用了样式的方法移除的,直接 display:none; 掉,可以参考:

           .rdw-inline-wrapper{
                // 隐藏删除按钮
                [title=Strikethrough]{
                    display: none;
                }
                // 代码
                [title=Monospace]{
                    display: none;
                }
                // 上角标
                [title=Superscript]{
                    display: none;
                }
                // 下角标
                [title=Subscript]{
                    display: none;
                }
            }
                
            // 标签
            .rdw-block-wrapper{
                display: none;
            }
            // 字体
            .rdw-fontfamily-wrapper{
                display: none;
            }
            .rdw-embedded-wrapper{
                display: none;
            }
            .rdw-list-wrapper{
                [title=Indent]{
                    display: none;
                }
                [title=Outdent]{
                    display: none;
                }
            }

五、效果展示

截屏2019-11-2915.44.56.png

上边列举了最近开发使用到的部分功能,如果还有什么问题,欢迎留言~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350