In the project, the rich text component is used. When inserting images into the editor, the default processing of the editor is to transfer the images to Base64 for saving, and submit the data request to the back end is too large. Therefore, the improvement is to upload images to the database first and store rich text data later

  • To upload pictures

    To customize the Handlers of Quill using the Module, run the following commands:

          <ReactQuill
            modules={{
              toolbar: {
                handlers: {
                    image:uploadImage
                },
              },
            }}
    
            theme="snow"
            ref={v= > (this.instance = v)}
          />
    Copy the code

    UploadImage uploadImage uploadImage uploadImage uploadImage uploadImage uploadImage

    const uploadImage=() = > {
          const quillEditor = this.instance.getEditor();
          const input = document.createElement('input');
          input.setAttribute('type'.'file');
          input.setAttribute('accept'.'image/*');
          input.click();
          input.onchange = async() = > {const file = input.files[0];
            const formData = new FormData();
            formData.append('quill-image', file);
            try {
              await uploadImage('image/upload', formData, function(data) { // Upload the image
                if (data.status === 200) {
                  const range = quillEditor.getSelection();
                  const link = data.result[0]; // Image address
                  quillEditor.insertEmbed(range.index, 'image', link); // Insert the image
                  message.success('Image uploaded successfully');
                } else {
                  message.error('Uploading picture failed'); }}); }catch (e) {
              console.log(e);
              message.error('Uploading picture failed'); }}; }Copy the code

    This is what happens when you click upload, but not when you copy and paste an image.

  • Copy and paste upload pictures

    The idea is to listen to the change of the value of rich text, through the re to match whether there is a picture,

    [^ / < img >] * SRC = ['] data: "image ([^ '"] +) [^ >] * > / gi / / match base64 stringCopy the code

    When the data containing Base64 is matched, the data of base64 is taken and stored in state, and then replaced with a flag bit first. After the uploading of Base64 is successful, the replacement is carried out through the regular matching flag bit. To commit reusability, you can package the useHooks code as follows

    import { useEffect, useState } from 'react';
    import { uploadImage } from 'services/uploadImage';
    import { message } from 'antd';
    import uuid from 'uuid/v4';
    
    // Base64 converts bloBs
    const dataURLtoBlob = dataurl= > {
      const arr = dataurl.split(', ');
      const mime = arr[0].match(/ : (. \ *?) ; /) [1];
      const bstr = atob(arr[1]);
      let n = bstr.length;
      const u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    };
    const useRichTextUploadPicture = value= > {
      const [replaceValue, setReplaceValue] = useState(' ');
      const [imgUrls, setImgUrls] = useState({}); // Record rich text images
    
      useEffect(() = > {
        setReplaceValue(value);
      }, [value]);
    
      useEffect(() = > {
        if(! replaceValue)return;
        // Content is the string to replace
        const newContent = replaceValue.replace(
          /<img [^>]\*src=['"]data:image([^'"]+)[^>]\*>/gi.(match, capture) = > {
            const id = uuid();
            const base64Url = match.substring(10, match.length - 2); imgUrls[id] = { id, base64Url }; setImgUrls({ ... imgUrls });return '<img src="' + id + '" / >'; }); setReplaceValue(newContent || replaceValue); }, [replaceValue, imgUrls]);// Replace the image after uploading successfully
      useEffect(() = > {
        const ids = Object.keys(imgUrls);
        if(! ids.length)return;
        ids.forEach(id= > {
          if(imgUrls[id]? .value && ! imgUrls[id]? .base64Url) { setReplaceValue(replaceValue.replace(id, imgUrls[id].value)); }}); }, [imgUrls]);// Upload the image
      useEffect(() = > {
        const ids = Object.keys(imgUrls);
        if(! ids.length)return;
        try {
          ids.forEach(async id => {
            if(imgUrls[id]? .base64Url) {var formData = new FormData();
              constfileImg = dataURLtoBlob(imgUrls[id]? .base64Url); formData.append('file', fileImg, 'image.jpg');
              try {
                uploadImage('image/upload', formData, data= > {
                  if (data.status === 200) {
                    imgUrls[id].value = data.result[0];
                    imgUrls[id].base64Url = undefined; setImgUrls({ ... imgUrls }); }else {
                    message.error('Uploading picture failed'); }}); }catch (e) {
                console.log(e);
                message.error('Uploading picture failed'); }}}); }catch (e) {
          console.log(e);
        }
      }, [imgUrls]);
    
      return [replaceValue, setReplaceValue];
    };
    
    export default useRichTextUploadPicture;
    
    Copy the code
  • conclusion

    It’s not the best solution, but it works.