React使用ckEditor5实现图片上传,自定义图片上传适配器

React使用ckEditor5实现图片上传,自定义图片上传适配器

简单的上传适配器

介绍:现成的简单的上传适配器,简单,只需要提供uploadUrl。

不足:不能定制,如:另外携带参数,返回处理等

配置

tsx 复制代码
import { SimpleUploadAdapter } from '@ckeditor/ckeditor5-upload';

// config中
  plugins: [ SimpleUploadAdapter, /* ... */ ],
  toolbar: [ /* ... */ ],
  simpleUpload: {
        // The URL that the images are uploaded to.
        uploadUrl: 'http://example.com',
  
        // Enable the XMLHttpRequest.withCredentials property.
        withCredentials: true,
  
        // Headers sent along with the XMLHttpRequest to the upload server.
        headers: {
            'X-CSRF-TOKEN': 'CSRF-Token',
            Authorization: 'Bearer <JSON Web Token>'
        }
    }

自定义上传适配器

介绍

介绍:自己定义上传适配器,可以定制一些项目特定的需求。 如下定制实现了:

  1. 上传携带参数userId等;
  2. 上传小于10KB转Base64显示,大于10KB则call api拿到res的url回显到editor

tip:ckEditor5上传 call api返回地址怎么拼可以拿到图片呢 <<< 你要在FE加上 [API HOST], e.g. http://10.89.104.58:8000/

自定义上传适配器

ck-Image-upload-adapter.ts(自定义上传适配器-封装代码)

tsx 复制代码
class MyUploadAdapter {
  userId: any;
  loader: any;
  draftMessageId: string;
  xhr: any;
  constructor(loader: any, userId: any, draftMessageId: string) {
    this.loader = loader;
    this.userId = userId;
    this.draftMessageId = draftMessageId;
  }

  upload() {
    return this.loader.file.then(
      (file: File) =>
        new Promise((resolve, reject) => {
          this._initRequest();
          this._initListeners(resolve, reject, file);
          this._sendRequest(file);
        }),
    );
  }

  abort() {
    if (this.xhr) {
      this.xhr.abort();
    }
  }

  _initRequest() {
    const xhr = (this.xhr = new XMLHttpRequest());
    // 修改为自己项目的接口地址
    xhr.open('POST', '/apis/sma-adm/api/mail/sma-upload-draft-msg-attch', true);
    xhr.responseType = 'json';
  }

  _initListeners(resolve: any, reject: any, file: File) {
    const xhr = this.xhr;
    const loader = this.loader;
    const genericErrorText = `图片${file.name}上传失败`;

    xhr.addEventListener('error', () => reject(genericErrorText));
    xhr.addEventListener('abort', () => reject());
    xhr.addEventListener('load', () => {
      // 这里限制了一下图片上传大小
      // const isLt2M = file.size / 1024 / 1024 < 2;
      // if (!isLt2M) {
      //   return reject(`图片${file.name}大小超出2M,请重新上传`);
      // }
      const response = xhr.response;
      if (!response || response?.status?.code !== 0) {
        return reject(response && response.error ? response.error.message : genericErrorText);
      }
      // baseUrl本地写死,线上从location拿origin
      const buildUrl = 'http://10.89.104.58:8080';
      const hostUrl = location.origin;
      const baseUrl = process.env.NODE_ENV === 'development' ? buildUrl : hostUrl;
      // 这里要根据后端接口取图片地址
      resolve({
        default: baseUrl + response.payload?.data?.attachmentPreviewUrl,
      });
    });
    if (xhr.upload) {
      xhr.upload.addEventListener('progress', (evt: any) => {
        if (evt.lengthComputable) {
          loader.uploadTotal = evt.total;
          loader.uploaded = evt.loaded;
        }
      });
    }
  }

  _sendRequest(file: File) {
    // 图片上传大小 >10KB call api返回imageurl显示到editor;<10KB转base64显示
    const isLt10KB = file.size / 1024 < 10;
    if (isLt10KB) {
      this.abort();
      return;
    }
    const data = new FormData();
    // 'file'要根据自己的接口字段填写
    data.append('draftMessageId', this.draftMessageId);
    data.append('userId', this.userId);
    data.append('attachType', 'IMAGE');
    data.append('file', file);
    this.xhr.send(data);
  }
}

export const CustomUploadAdapterPlugin = (editor: any, userId: any, draftMessageId: string) => {
  editor.plugins.get('FileRepository').createUploadAdapter = (loader: any) => {
    return new MyUploadAdapter(loader, userId, draftMessageId);
  };
};

编辑器使用

tip:editor组件中使用,editorConfig参考文章:react使用CKEditor5,两种使用方式(在线构建器和从源代码构建)。附国际化

tsx 复制代码
  // 获取项目中登录等信息
  const currentUser = useSelector((state: RootState) => state.userSliceReducer.currentUser);
  const { draftMessageId } = useSelector((state: RootState) => state.composeMailDraftIdReducer);
  // 设置上传适配器插件,并传参
  editorConfig.extraPlugins = [
    (editor: any) => CustomUploadAdapterPlugin(editor, currentUser?.userId, draftMessageId),
  ];

  return (
      <div className="ckeditor">
        <CKEditor
          editor={ClassicEditor}
          config={editorConfig}
          data={html}
          onChange={(_event, editor) => {
            const data = editor.getData();
            handleSetHtml(data);
          }}
        />
      </div>
    );

大功告成,去试试吧!

参考:CKEditor5基本使用,图片上传,添加插件

相关推荐
无知的小菜鸡9 分钟前
路由:ReactRouter
react.js
zqx_71 天前
随记 前端框架React的初步认识
前端·react.js·前端框架
TonyH20022 天前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包
掘金泥石流2 天前
React v19 的 React Complier 是如何优化 React 组件的,看 AI 是如何回答的
javascript·人工智能·react.js
lucifer3112 天前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
秃头女孩y2 天前
React基础-快速梳理
前端·react.js·前端框架
sophie旭2 天前
我要拿捏 react 系列二: React 架构设计
javascript·react.js·前端框架
BHDDGT3 天前
react-问卷星项目(5)
前端·javascript·react.js
liangshanbo12153 天前
将 Intersection Observer 与自定义 React Hook 结合使用
前端·react.js·前端框架