@vueup/vue-quill粘贴图片上传

1、前言

富文本编辑器上传图片默认为base64,存入数据库过于庞大,由于若依以及quill-editor不支持粘贴图片上传,  因此加入了监听 paste 方法 实现图片地址上传,并替换到富文本编辑器中

2、核心代码实现

 let quill = quillEditorRef.value.getQuill();
    let toolbar = quill.getModule("toolbar");
    // 粘贴事件
    quill.root.addEventListener("paste", (evt) => {
      if (!props.isPasteUpload) {
        return
      }
      let rtf;
      let videoType = /^video\/.*/;
      if (evt.clipboardData.files.length > 0) {
        rtf = evt.clipboardData.files[0];
        if (videoType.test(rtf.type)) {

        } else {
          proxy.$refs.editorUploadRef.handleStart(rtf);
          fileNum.value = 1;
        }
        // let file = base64toFile(`data:image/png;base64,${rtf}`)

      } else {
        rtf = evt.clipboardData.getData('text/rtf');
        // 提取图片信息
        const hexStrings = extractImageDataFromRtf(rtf);
        // 获取base64图片数据
        const base64Images = hexStrings.map((hexObj) => {
          return convertHexToBase64(hexObj.hex);
        })
        const fileList = [];
        // 调用上传接口
        for (let i = 0; i < base64Images.length; i++) {
          let file = base64toFile(`data:image/png;base64,${base64Images[i]}`)
          proxy.$refs.editorUploadRef.handleStart(file);
          fileList.push(file)
        }
        fileNum.value = fileList.length;

      }
      isFile.value = true;
      // proxy.$refs.editorUploadRef.handleStart(fileList);
      if (videoType.test(rtf.type)) {
        proxy.$message.error("暂不支持粘贴视频!");
      } else {
        proxy.$refs.editorUploadRef.submit();
      }


    })
// 将base64转file
const base64toFile = (dataurl, filename = 'file') => {
  let arr = dataurl.split(',')
  let mime = arr[0].match(/:(.*?);/)[1]
  let suffix = mime.split('/')[1]
  let bstr = atob(arr[1])
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  let file = new File([u8arr], `${filename}.${suffix}`, {
    type: mime
  })
  return file
}

// 将hex格式转化为base64
const convertHexToBase64 = (hexString) => {
  return btoa(hexString.match(/\w{2}/g).map(char => {
    return String.fromCharCode(parseInt(char, 16));
  }).join(''));

}
/**
    * 
    * rtf中提取图片信息
    * 利用正则从rtf内容中提取到图片的核心信息,得到数组。其中数组中保存的信息有
       {
       type: ‘’, //图片类型
       hex: ‘’ // hex字符串
       }
    * @param {*} rtfData 
*/
const extractImageDataFromRtf = (rtfData) => {
  if (!rtfData) {
    return [];
  }
  const regexPictureHeader = /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/
  const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}', 'g');
  const images = rtfData.match(regexPicture);
  const result = [];
  if (images) {
    for (const image of images) {
      let imageType = false;

      if (image.includes('\\pngblip')) {
        imageType = 'image/png';
      } else if (image.includes('\\jpegblip')) {
        imageType = 'image/jpeg';
      }

      if (imageType) {
        result.push({
          hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
          type: imageType
        });
      }
    }
  }
  return result;
}
// 上传成功处理
function handleUploadSuccess(res, file) {
  // 如果上传成功
  if (res.code == 200) {
    // 获取富文本实例
    let quill = toRaw(quillEditorRef.value).getQuill();
    // 获取光标位置
    let length = quill.selection.savedRange.index;
    if (isFile.value) {
      pasteFileList.value.push(res.fileName)
      if (pasteFileList.value.length == fileNum.value) {
        setResponseUrl();
        quill.setSelection(length + 1);
      }
    } else {
      // 插入图片,res.url为服务器返回的图片链接地址
      quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName);
      // 调整光标到最后
      quill.setSelection(length + 1);
    }

  } else {
    proxy.$modal.msgError("图片插入失败");
  }
}
// 粘贴图片插入
const setResponseUrl = () => {
  const editorDom = proxy.$refs.quillEditorRef.getQuill().root;
  const editorImgs = editorDom.querySelectorAll('img[src*="//:0"]');
  // const editorImgs = editorDom.querySelectorAll('img');

  // 替换图片Url
  editorImgs.forEach((item, index) => {
    item.src = import.meta.env.VITE_APP_BASE_API + pasteFileList.value[index];
  })
  isFile.value = false;
  fileNum.value = 0;
  pasteFileList.value = [];
}

3、代码解释

上传逻辑不再追述,这里只做了粘贴图片上传的相关代码逻辑。其他请自行修改。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值