@wangeditor/editor富文本paste图片base64编码

469 阅读1分钟

富文本@wangeditor/editor组件中,粘贴来自有道云中或者其他途径的富文本内容,其中图片为base64编码的格式。本身这种格式并不会导致问题,但是大量的base64图片会导致请求体过大。这时候需要将base64格式的图片上传到服务器中。

粘贴带有base64格式的图片,并不会触发@wangeditor/editor的图片上传钩子。所以需要在@wangeditor/editor 提供的customPaste去处理

import { Boot, createEditor, createToolbar } from '@wangeditor/editor'

new createEditor({
    ... // 此处省略其他代码
    customPaste() {
      let html = event.clipboardData.getData('text/html') // 获取粘贴的 html

      // 获取粘贴的所有base64格式的图片
      const base64Imgs = findAllImgSrcsFromHtml(html)

      if (base64Imgs.length > 0) {
        Promise.all(
          base64Imgs.map(imgSrc => {
            const file = dataURLtoFile(imgSrc)
            // 上传图片到服务器,并获取上传后图片的路径
            return customUpload(file).then(url => {
              html = html.replace(imgSrc, url)
            })
          })
        ).then(() => {
          editor.dangerouslyInsertHtml(html)
        })
        // 阻止默认的粘贴行为
        event.preventDefault()
        return false
      } else {
        return true
      }
    }
})

上面使用到的工具函数

function isBase64Image(src) {
  const base64Pattern = /^data:(image\/(?:jpeg|png|gif|bmp|webp|tiff|svg+xml);base64,)/
  return base64Pattern.test(src)
}

function findAllImgSrcsFromHtml(htmlData) {
  let imgReg = /(?<=(img[^>]*src="))[^"]*/g

  let srcArr = htmlData.match(imgReg)

  if (srcArr && srcArr.length > 0) {
    return srcArr.filter(isBase64Image)
  }

  return []
}

function generateRandomFilename(extension) {
  const randomChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let filename = ''
  for (let i = 0; i < 10; i++) {
    filename += randomChars.charAt(Math.floor(Math.random() * randomChars.length))
  }
  return `${filename}.${extension}`
}

function dataURLtoFile(dataurl) {
  //将base64转换为文件
  var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = window.atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  
  const MIME_TYPE_EXTENSIONS = {
    // JPEG 图像
    'image/jpeg': 'jpg',
    // PNG 图像
    'image/png': 'png',
    // GIF 图像
    'image/gif': 'gif',
    // 位图(BMP)
    'image/bmp': 'bmp',
    // WebP 图像格式
    'image/webp': 'webp',
    // TIFF 图像格式
    'image/tiff': 'tiff',
    // SVG 可缩放矢量图形
    'image/svg+xml': 'svg',
  }

  const extension = MIME_TYPE_EXTENSIONS[mime.split('/')[1]]
  return new File([u8arr], `${generateRandomFilename()}.${extension}`, { type: mime })
}