改造wangEditor成react组件

我们知道wangEditor常用的功能是editor实例的 txt.html()txt.text() 方法,尤其是 txt.html() 方法,这是一个类似与jQuery常用的那种get和set一体的方法。

我们怎么把这种传统模式书写的第三方库引入到react项目中,并且方便其它同事使用呢?我们需要做一个react组件,让它来完成wangEditor的“react化”。

对于编辑器这种,我们不太在乎它的生命周期,我们更适合将它封装成函数式组件。

我们在项目使用是只有使用 ref 拿到这个组件并且调用对应的方法来取到(设置)富文本里面的内容。

这样在使用时就很方便啊,那我们的WangEditor组件怎么实现呢?

import React, { useEffect, forwardRef, useImperativeHandle } from 'react';
import toaster from 'viewsUI/toaster';

import WangEditor from 'viewsUI/wangeditor/wangEditorForSetting'
import wangEditorI18nLang from './i18nLang';

let richEditor = null;

/*eslint-disable*/
const wangEditor = (props, ref) => {

  let unique = Math.random().toString(36).substr(2);

  useEffect(() => {
    console.log('wangEditor useEffect -> ');
    loadEditor();
    if (props.visible) {
      setContent(props.content || '');
    }
  }, []);

  function getContent() {
    return richEditor.txt.html();
  }

  function getText() {
    return richEditor.txt.text();
  }

  function setContent (content) {
    richEditor.txt.html(content);
    initFocus();
  }

  function initFocus() {
    const $textElem = richEditor.$textElem;
    const $children = $textElem.children();

    if ($children.length) {
      const $first = $children.first();
      richEditor.selection.createRangeByElem($first, false, true);
      richEditor.selection.restoreSelection();
    }
  }

  useImperativeHandle(ref, () => ({
    getContent,
    getText,
    setContent,
    initFocus,
  }));

  function loadEditor() {
    richEditor = new WangEditor('#toolbar' + unique, '#body' + unique);
    richEditor.customConfig.uploadImgShowBase64 = false;
    richEditor.customConfig.uploadImgMaxLength = 1
    richEditor.customConfig.uploadImgParams = {
      fileBytes: '',
      maxBytes: 204800,
      thumbHeight: 120,
      thumbWidth: 120,
    };
    richEditor.customConfig.menus = [
      'head', // 标题
      'bold', // 粗体
      'fontSize', // 字号
      'fontName', // 字体
      'italic', // 斜体
      'underline', // 下划线
      // 'strikeThrough', // 删除线
      'foreColor', // 文字颜色
      'backColor', // 背景颜色
      'link', // 插入链接
      'list', // 列表
      'justify', // 对齐方式
      'quote', // 引用
      //'emoticon', // 表情
      'image', // 插入图片
      // 'table', // 表格
      'htmlTable', // 粘贴表格
      // 'video', // 插入视频
      // 'code', // 插入代码
      'undo', // 撤销
      'redo' // 重复
    ];
    richEditor.create();
  }

  return (
    
); }; export default forwardRef(wangEditor);

为了给父组件暴露wangEditor组件的部分方法,我们需要使用 useImperativeHandle

它可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。 通常 useImperativeHandle 应当与 forwardRef 一起在函数式中使用。

forwardRef介绍

用法一:让我们在父组件里面能通过 ref 拿到函数式子组件的某个node节点

const Menu = (props, ref) => {
  return ();
};
export default forwardRef(Menu);

具体使用细节可以参照我前几天写的 《Did you mean to use React.forwardRef()?搞懂react的createRef和forwardRef》

用法二:让我们在父组件里面能通过 ref 拿到函数式子组件需要通过 useImperativeHandle 暴露的方法

const Menu = (props, ref) => {
  function log(...rest) {
    console.log(...rest);
  }

  useImperativeHandle(ref, () => ({
    log
  }));

  return ();
};
export default forwardRef(Menu);

useImperativeHandle介绍

useImperativeHandle(ref, createHandle, [deps])

ref :定义 current 对象的 ref createHandle :一个函数,返回值是一个对象,即这个 ref 的current [deps] :即依赖列表,当监听的依赖发生变化,useImperativeHandle 才会重新将子组件的实例属性输出到父组件ref 的 current 属性上,如果为空数组,则不会重新输出。

现在我们就可以通过 this.richEditorRef.current.getContent() 获取到富文本里面的内容了。