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

需要形容

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

呈现的问题

而后我问了公司的其余共事,有什么比拟好的举荐,说了几个,最初我还是抉择了最简略的 wangEditor (过后我感觉它最简略,因为不须要怎么配置,网站也有现成的 demo ),一开始是很顺畅的,可能灵便的设置菜单和根本响应,解决机制等,然而当我在一个页面中应用两个富文本时,出bug了,具体形容单击链接跳转看。简略的说就是两个富文本不能同时承受拖拽进来的图片。

解决办法

至于解决办法,当然是先去 github 报个异样,而后换一个编辑器看看,客户在等着,也没工夫钻研。随后我尝试了antd社区精选组件,外面有两个react-quill 和 braft-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_PROXYclass 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>