TinyEditor 篇2:剪贴板粘贴图片并同步上传至服务器

书接上回,我们实现了富文本编辑器的工具栏图片上传按钮选择图片后,可以将图片上传至服务器,这一篇,来看看当我们复制了一张图片到剪贴板,粘贴到编辑器文本编辑区域时,如何同步上传至服务器呢?

功能实现

我们的实现步骤是:

当我们点击 Ctrl + V 的时候,FluentEditor 默认粘贴(插入 base64 图片),此处触发我们自己的粘贴处理方法 handlePaste,此时上传图片,调用FluentEditor 的 .insertEmbed 方法插入图片地址。这里直接上代码:

javascript 复制代码
<template>
  <div class="editor-container">
    <div ref="editorRef" class="editor-inside"></div>
  </div>
</template>
 
<script setup>
import { onMounted, ref } from 'vue'
import '@opentiny/fluent-editor/style.css'
import FluentEditor from '@opentiny/fluent-editor'
import axios from 'axios'
import { uploadFile } from '@/model/editor.js' // 这里使用自己的上传接口即可
 
const editorRef = ref(null)
let editorInstance = null
 
const TOOLBAR_CONFIG = [
  [{ header: [] }],
  ['bold', 'italic', 'underline', 'link'],
  [{ list: 'ordered' }, { list: 'bullet' }],
  ['clean'],
  ['image']
]
 
const selectImage = () => {
  const input = document.createElement('input')
  input.type = 'file'
  input.accept = 'image/*'
  input.click()
 
  input.onchange = async () => {
    const file = input.files[0]
    if (!file) return
 
    try {
      const url = await uploadImage(file)
 
      const range = editorInstance.getSelection()
      editorInstance.insertEmbed(range.index, 'image', url)
 
    } catch (err) {
      console.error('上传失败', err)
    }
  }
}
 
const uploadImage = async (file) => {
  const ext = file.name.split('.').pop()
 
  const res = await uploadFile({ ext })
 
  const resData = res.data
  const uploadUrl = resData.upload_url
  const fileUrl = resData.public_url
 
  await axios.put(uploadUrl, file, {
    headers: {
      'Content-Type': file.type
    }
  })
 
  return fileUrl
}

const handlePaste = async (e) => {
  const items = e.clipboardData?.items
  if (!items) return

  for (let i = 0; i < items.length; i++) {
    const item = items[i]

    if (item.type.indexOf('image') !== -1) {
      e.preventDefault()
      e.stopPropagation()

      const file = item.getAsFile()

      try {
        const url = await uploadImage(file)

        const range = editorInstance.getSelection(true)
        editorInstance.insertEmbed(range.index, 'image', url)
      } catch (err) {
        console.error('粘贴上传失败', err)
      }

      break
    }
  }
}
 
onMounted(() => {
  if (!editorRef.value) return
 
  editorInstance = new FluentEditor(editorRef.value, {
    theme: 'snow',
    modules: {
      toolbar: {
        container: TOOLBAR_CONFIG,
        handlers: {
          image: selectImage
        }
      }
    }
  })

  editorRef.value.addEventListener('paste', handlePaste, true)
})
</script>
 
<style scoped>
.editor-container {
  width: 50%;
  display: flex;
  justify-content: center;
  padding-top: 20px;
}
 
.editor-inside {
  height: 350px;
}
 
.editor-inside :deep(.ql-container) {
  height: 350px;
}
 
.editor-inside :deep(.ql-editor) {
  height: 310px;
}
</style>

注意:我们在监听 paste 的时候,第三个入参传了 true,是为了阻止编辑器默认的图片粘贴行为,如果不写,那么我们在粘贴图片的时候,会粘贴进去两张图片。

下一篇,我们看看将图片拖拽到编辑器中如何渲染和上传。

相关推荐
原来是猿2 小时前
Linux - 基础IO【中】
linux·运维·服务器
Xzq2105092 小时前
网络编程套接字(UDP)
运维·服务器·网络
无巧不成书02182 小时前
React Native 深度解析:跨平台移动开发框架(2026实战版)
javascript·react native·react.js
青柠代码录2 小时前
【Vue3】SCSS 基础篇
前端·scss
为美好的生活献上中指2 小时前
*Java 沉淀重走长征路*之——《Java Web 应用开发完全指南:从零到企业实战(两万字深度解析)》
java·开发语言·前端·html·javaweb·js
阳火锅2 小时前
AI时代的到来,我想打造这样一款产品。
前端·javascript·vue.js
翼龙云_cloud2 小时前
阿里云代理商:阿里云百炼视频混剪实战
服务器·阿里云·云计算
网硕互联的小客服2 小时前
CentOS 7 实现自动备份数据到百度网盘的具体步骤与方法
运维·服务器·网络·安全·自动化