Skip to content

React + BraftEditor 实现基础富文本

当前字数: 0 字 阅读时长: 0 分钟

😊 BraftEditor

(BraftEditor)一个基于 draft-js 的 Web 富文本编辑器,适用于 React 框架,兼容主流现代浏览器。

😊 安装 BraftEditor

bash
yarn add braft-editor

😊 实现 基础的富文本组件

  1. 创建组件
bash
mkdir RichText
cd RichiText
touch index.tsx controls.ts
  1. controls.ts 这里主要是富文本编辑器的一些默认配置,更多配置可以查询(文档)
ts
export const richTextControls: any = [
  "undo",
  "redo",

  "separator",
  "headings",
  "font-size",
  "line-height",
  "letter-spacing",

  "separator",
  "text-color",
  "bold",
  "italic",
  "underline",
  "strike-through",

  "separator",
  "superscript",
  "subscript",
  "remove-styles",
  "emoji",

  "separator",
  "text-indent",
  "text-align",

  "separator",
  "list-ul",
  "list-ol",
  "blockquote",
  "code",

  "separator",
  "link",

  "separator",
  "hr",

  "separator",
  "media",

  "separator",
  "clear",
  "fullscreen",
];
  1. index.tsx
tsx

import { useEffect, useState, CSSProperties } from 'react';
// 系统静态文件公共上传方法
import { staticResourceUpload, richTextQuery} from '../../common/services/system';
import { richTextControls } from './controls';

// 引入编辑器及样式
import BraftEditor, { MediaType } from 'braft-editor';
import 'braft-editor/dist/index.css';

// 这里可以利用 useEffect 自定义一个执行函数
const useMount = (callback: () => void) => {
  return useEffect(() => {
    return callback();
  }, []);
};

type Props = {
  id: string;
  readOnly?: boolean;
  onChange?: (content?: string) => void;
};

export default (props: Props) => {
  const { readOnly } = props;

  // 创建 state 用来存储 内容
  const [richValue, setRichValue] = useState<string>(BraftEditor.createEditorState(null));

  // 这里可以同步向外传递 富文本内容
  const handleSetRichValue = (v: string | { toHTML: any }) => {
    setRichValue(BraftEditor.createEditorState(v));
    props?.onChange?.(typeof v === 'string' ? v : v?.toHTML());
  };

  // 根据 ID 查询当前内容
  const fetchRichTextContent = async () => {
    if (!props?.id) return;
    const res = await richTextQuery?.({ id: props.id });
    if (res?.status !== 'SUCCESS') return;
    const { content } = res;
    handleSetRichValue(content || '');
  };

  // 处理媒体上传 图片 | 视频
  const handleFetchUploadFinish = (res: FETCH.Res, uploadCall: any) => {
    if (res?.status !== 'SUCCESS') {
      uploadCall.error(res?.message);
      return;
    }
    /** 指定音视频是否循环播放|是否自动播放|是否显示控制栏 */
    const meta = { loop: true, autoPlay: true, controls: true, },
    uploadCall.success({ url: res?.videoPath, meta });
  };

  const handleMediaUpload :MediaType['uploadFn'] = async (uploadCall) => {
    if (!uploadCall?.file) return;
    /** 这里使用 FORMDATA 发送文件流的方案 */
    const formData = new FormData();
    formData.append('file', uploadCall?.file);
    const res = await staticResourceUpload(formData);
    handleFetchUploadFinish(res, uploadCall)
  };

  // 来一点样式
  const contentStyle: CSSProperties = {
    boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)',
    height: 460,
  };

  // 初始化查询
  useMount(fetchRichTextContent)

  return (
    <section className="rich-text-wrapper">
      <BraftEditor
        media={{ uploadFn: handleMediaUpload }}
        onChange={handleSetRichValue}
        controls={richTextControls}
        contentStyle={contentStyle}
        readOnly={readOnly}
        contentFormat="html"
        placeholder="请输入"
        value={richValue}
      />
    </section>
  );
};

😊 createEditorState 方法

可以使用 BraftEditor.createEditorState 方法来将 raw或者 html格式的数据转换成 editorState 数据

tsx
// 引入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);

editorState 数据转换成 raw 或者 html

tsx
// 将editorState数据转换成RAW字符串
const rawString = editorState.toRAW();

// editorState.toRAW()方法接收一个布尔值参数,用于决定是否返回RAW JSON对象,默认是false
const rawJSON = editorState.toRAW(true);

// 将editorState数据转换成html字符串
const htmlString = editorState.toHTML();

TIP

在实际项目中,editorState 对象无法用于展示也无法用于持久化存储,

需要将其转换为 html 字符串来进行展示,用于持久化时则建议转换成 raw 格式。

raw 格式是一种可以用于无损持久化的数据格式,形式上是一段 JSON, 推荐使用这种格式来用于数据持久化。

虽然 html 字符串也可以用于持久化存储,但是对于比较复杂的富文本内容,在反复编辑的过程中,可能会存在格式丢失的情况,

比较标准的做法是在数据库中同时存储 raw 字符串和 html 字符串,分别用于再次编辑和前台展示。

Released under the MIT License.