BraftEditor 扩展 andt Upload组件

308 阅读1分钟

集成 ant design 上传组件

集成 ant design 上传组件逻辑参考 braft.margox.cn/demos/antd-… , 该组件更主要的是把editorState, setEditorState通过useImperativeHandle暴露给父组件。

import { forwardRef, useImperativeHandle } from 'react';
import BraftEditor, { ControlType, ExtendControlType } from 'braft-editor';
import { useState } from 'react';
import { Upload as AntdUpload } from 'antd';
import { ContentUtils } from 'braft-utils';

import Message from '../Library/Message';
import './index.less';

export const BraftEditorInstance = BraftEditor;

export default forwardRef(function HWBraftEditor(props, ref) {
  const [editorState, setEditorState] = useState(BraftEditor.createEditorState(null));
  const controls: ControlType[] = [
    'font-size',
    'bold',
    'italic',
    'underline',
    'text-color',
    'text-align',
    'separator',
    'link',
    'separator',
  ];

  // 将 editorState 和更新 editorState 的方法暴露给父组件,父组件就无需每次使用时创建
  // useImperativeHandle api 可自定义暴露组件内部的方法,但需要配合forwardRef使用
  useImperativeHandle(
    ref,
    () => ({
      editorState,
      setEditorState,
    }),
    [editorState],
  );

  const onUploadChange = ({ file, fileList }) => {
    if (file.status === 'done') {
      setEditorState(
        ContentUtils.insertMedias(editorState, [
          {
            type: 'IMAGE',
            url: file.response.data,
          },
        ]),
      );
    }
  };

  const beforeUpload = (file) => {
    if (file.size > 5 * 1024 * 1024) {
      Message.error('上传文件不能超过50M');
      return false;
    }
  };

  // TODO
  const uploadProps = {
    name: 'image',
    action: `${API_PREFIX}/api/back/OssImage`,
    headers: {
      token: localStorage.getItem('backToken') || '',
    },
    onChange: onUploadChange,
    beforeUpload,
  };

  const handleChange = (editorState) => {
    setEditorState(editorState);
  };

  const extendControls: ExtendControlType[] = [
    {
      key: 'antd-uploader',
      type: 'component',
      component: (
        <AntdUpload accept={'.jpg,.jpeg,.png,.gif'} showUploadList={false} {...uploadProps}>
          <button type='button' className='control-item button upload-button' data-title='插入图片'>
            插入图片
          </button>
        </AntdUpload>
      ),
    },
  ];

  return (
    <BraftEditor
      value={editorState}
      onChange={handleChange}
      controls={controls}
      extendControls={extendControls}
    />
  );
});

编辑页中使用 BraftEditor

父组件通过暴露的方法更新或者提交表单,而不用每次都创建editorState, setEditorState,达到简化使用的目的。

import { useParams } from 'umi';
import { useEffect, useRef } from 'react';
import { Button, Form, Space } from '@/components/Library';
import { Container } from '@/components/Dashboard';
import BraftEditor, { BraftEditorInstance } from '@/components/BraftEditor';
import request from '@/api';
import urlMap from '@/api/url-map';

const { articleManage } = urlMap;

export default function AddArticle() {
  const id = Number(useParams().id);
  const [form] = Form.useForm();
  const editorRef = useRef<any>(null);

  const onFinish = (values: any) => {
    // 提交表单时转为HTML格式
    values.content = editorRef.current.editorState.toHTML();
  };

  useEffect(() => {
    // 获取详情
    request.get(articleManage.detail, { postId: id }).then((res) => {
      res.data.content = BraftEditorInstance.createEditorState(res.data.content);
      editorRef.current.setEditorState(res.data.content); // 给受控富文本组件赋值

      // initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新
      form.setFieldValue('content', res.data.content);
    });
  }, []);

  return (
    <Container>
      <Form
        name='basic'
        labelCol={{ span: 3 }}
        wrapperCol={{ span: 12 }}
        form={form}
        onFinish={onFinish}
        autoComplete='off'
      >
        <Form.Item label='内容' name='content'>
          <BraftEditor ref={editorRef} />
        </Form.Item>

        <Form.Item wrapperCol={{ offset: 3 }}>
          <Space>
            <Button onClick={() => history.back()}>取消</Button>
            <Button type='primary' htmlType='submit'>
              保存
            </Button>
          </Space>
        </Form.Item>
      </Form>
    </Container>
  );
}