Braft Editor 结合 Antd V4 的 Form 表单 实现

贾雨村
• 阅读 5103

想直接看实现的请跳过前三节.....

需求描述

因为业务需求,需要用到比较多的富文本编辑器,至于为什么会在一个页面里有很多的富文本,憋问我,问就是甲方爸爸给钱了!在富文本中,需要满足能够随意的修改图片的大小,能够直接复制图片进入,能够满足基本的排版需求,按理来说基本上网上的编辑器都能满足要求。

出现的问题

然后我问了公司的其他同事,有什么比较好的推荐,说了几个,最后我还是选择了最简单的 wangEditor (当时我觉得它最简单,因为不需要怎么配置,网站也有现成的 demo ),一开始是很顺畅的,能够灵活的设置菜单和基本响应,处理机制等,然而当我在一个页面中使用两个富文本时,出bug了,具体描述单击链接跳转看。简单的说就是两个富文本不能同时接受拖拽进来的图片。

解决办法

至于解决办法,当然是先去 github 报个异常,然后换一个编辑器看看,客户在等着,也没时间研究。随后我尝试了antd社区精选组件,里面有两个react-quillbraft-editor,分别编写了 demo ,发现后者更满足我的项目需求。

代码

现在开始进入正题,我先对braft-editor进行了简答封装,因为它自带的上传是会将图片转成 base64 格式的,与我的需求不符,并且如果直接传 base64 的字符串,数据太大,很容易引起接口传输过慢,中断的问题。封装代码如下:

Editor文件

/**
 * @desc 新的antd富文本编辑器
 * @name Editor
 * @author Cyearn
 * @date 2020/12/11
 */

import React, { Component } from 'react'
import BraftEditor from 'braft-editor'  // 引入库
import 'braft-editor/dist/index.css'   // 引入样式
import { apiPostUpload } from '@/api/load'  // 引入自己的上传接口
import { isDev } from '@/utils'  // 判定是否为开发模式的函数
import { message } from 'antd'

// 本地调试时的服务地址
const HOST = process.env.REACT_APP_DEFAULT_PROXY

class Editor extends Component {
  constructor(props) {
    super(props)
    this.state = {
      propValue: '', // 一个用来判定是否需要初始化编辑器的变量
      editorState: BraftEditor.createEditorState(null), // 设置编辑器初始内容
      outputHTML: null, // 富文本的内容
    }
    this.editorRef = React.createRef()  // 因为用到了自定义的上传,所以对编辑器加了一个ref
  }
  componentDidMount() {}
  // 用来判定是否需要初始化编辑器
  componentDidUpdate() {
    if (this.props.value && this.props.value !== this.state.propValue) {
      if (this.state.propValue === '') {
      // 上层传入的是字符串结构的数据,所以需要使用BraftEditor.createEditorState来包裹它
        this.setState({ editorState: BraftEditor.createEditorState(this.props.value), propValue: this.props.value })
      }
    }
  }


  // 编辑器发生变化
  handleChange = async editorState => {
    await this.setState({
      editorState: editorState,
      outputHTML: editorState.toHTML(),
    })
    this.props.onChange(editorState.toHTML()) // 当编辑器内容发生变化的时候向上抛出更改的结果
  }

  // 编辑器失去焦点
  onBlurEditor = () => {
    const { outputHTML } = this.state
    // this.props.onChange(outputHTML)
  }

  // 上传函数
  uploadImage = async param => {
    try {
      let agr = {
        file: param.file,
        isOpenFile: true,
      }
      const res = await apiPostUpload(agr) // 自己的上传接口
      let data = res.datas
      param.progress(100) // 显示完成上传的进度条
      param.success({
        url: isDev ? HOST + data.url : data.url,
        meta: {
          alt: data.name,
          //   loop: true, // 指定音视频是否循环播放
          //   autoPlay: true, // 指定音视频是否自动播放
          //   controls: true, // 指定音视频是否显示控制栏
        },
      })
      const { getValue } = this.editorRef // 通过ref获取到当前的编辑器内的数据
      this.handleChange(getValue()) // 调用数据更新的函数,很重要,不做这个会出现保存结果和显示结果不匹配的情况
    } catch (error) {
      let msg = error + ',上传失败'
      message.error(msg)
    }
  }
  // 查看图片发生变化的函数
  changeImage = async file => {
    console.log(file)
  }

  render() {
    const { editorState } = this.state
    const { width = '100%', id = 'braft_editor', height = 600 } = this.props // 定义一些默认的格式
    // 这是配置自己菜单的部分,删除就是显示全菜单
    const controls = [
      {
        key: 'bold',
        text: <b>加粗</b>,
      },
      'italic',
      'underline',
      'separator',
      'link',
      'separator',
      'media',
    ]
    return (
      <div className='editor-wrapper' style={{ width: width, border: '1px solid #999999' }} id={id}>
        <BraftEditor
          ref={e => (this.editorRef = e)}  // 回调refs,用来绑定ref
          value={editorState}  
          onChange={this.handleChange}
          controls={controls}  // 用来配置自己的菜单
          contentStyle={{ height: 300, boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)' }}  // 用来设置一些样式
          media={{ uploadFn: this.uploadImage, pasteImage: true, onChange: this.changeImage }}  // 用来定义自己的上传函数
        />
      </div>
    )
  }
}

export default Editor

Form 表单所在文件

// 构造函数
constructor(props) {
    super(props)
    this.state = { content: ''}
    this.formRef = React.createRef()
  }
 // 当form发生变化
  onFormChange = e => {
    console.log(e)
    Boolean(e['content']) &&
      this.setState({
        content: e['content'],
      })
  }
  
  //...render内部的代码
 <Form
            {...layout}
            name='docForm'
            style={{ width: '100%' }}
            ref={this.formRef}
            scrollToFirstError={true}
            onValuesChange={this.onFormChange}
          >
     <Form.Item
                  name={'content'}
                  label='内容编辑'
                  rules={[
                    { required: true, type: 'string', min: 1 },
                    // 需要自定义一个校验函数,因为braft-editor默认文本就是 <p></p>,form自带的校验不会判定为空
                    ({ getFieldValue }) => ({
                      validator(rule, value) {
                        console.log(value)
                        if (value === '<p></p>') {
                          return Promise.reject('请输入文章内容')
                        } else {
                          return Promise.resolve()
                        }
                      },
                    }),
                  ]}
                >
                
                  {/* <Editor width={'85%'} value={content} onChange={this.changeContent}/>  如果不在form中使用就要自己写受控变量和chang函数*/}
                  <Editor width={'85%'} />
                </Form.Item>
</Form>
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
UIWebView长按保存图片和识别图片二维码的实现方案(使用缓存)
0x00需求:长按识别UIWebView中的二维码,如下图长按识别二维码0x01方案1:给UIWebView增加一个长按手势,激活长按手势时获取当前UIWebView的截图,分析是否包含二维码。核心代码:略优点:流程简单,可以快速实现。不足:无法实现保存UIWebView中图片,如果当前We
编程范儿 编程范儿
3年前
项目中的富文本编辑器该如何选择?
项目中经常需要用到富文本编辑器的时候,而常见的富文本编辑器都有哪些?该如何选择?先看看市面上都有哪些可用的富文本编辑器:(插件式的,支持Vue,React,Angular框架)(Typescript开发的Web富文本编辑器,轻量、简洁、易用、开源免费,支持JS直接引入使用,或者Vue2/3,React)(开源,插件多,功能齐全,支持
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
Neditor 富文本编辑器介绍
Neditor富文本编辑器介绍Neditor是我们团队基于Ueditor的一款富文本编辑器。不论从功能还是从其它各方面来讲,Ueditor都是一款无以替代的编辑器产品。只是已经不符合现代化样式的需求,于是我们修改它的样式,实现了这样的效果:!image(https://www.notadd.com/s
Stella981 Stella981
3年前
Gson之实例五
前面四篇博客基本上可以满足我们处理的绝大多数需求,但有时项目中对json有特殊的格式规定.比如下面的json串解析:{"tableName":"students","tableData":{"id":1,"name":"李坤","birthDay":"Jun 22, 2012 9:54:49 PM"},{"id":2,"name":"曹贵生"
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
新增富文本单元格和XSS过滤器
一.富文本单元格        皕杰设计器新增了单元格富文本类型,我们在一些网站编辑文章的时候经常可以看到富文本和markdown等编辑器,其中以Word为例,输入文字后,选择不同的功能(通常是通过点击某个图标),例如加粗或者调整字体大小,处理
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(