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,是为了阻止编辑器默认的图片粘贴行为,如果不写,那么我们在粘贴图片的时候,会粘贴进去两张图片。

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

相关推荐
钰fly13 小时前
Halcon联合编程适应图像的方法(picture)
开发语言·前端·javascript
束尘13 小时前
Vue3一键复制图片到剪贴板
开发语言·javascript·vue.js
木斯佳13 小时前
前端八股文面经大全:字节跳动前端一面·深度解析(Plus Ultra版)(2026-03-30)·面经深度解析
前端·设计模式·八股·光栅化
AC赳赳老秦13 小时前
自媒体博主:OpenClaw多Agent协同,实现选题-创作-审核全流程自动化
运维·服务器·开发语言·人工智能·自动化·媒体·openclaw
酉鬼女又兒13 小时前
零基础快速入门前端DOM 节点操作核心知识点及蓝桥杯 Web 应用开发考点解析(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯
LXXgalaxy13 小时前
Vue3 + TypeScript 组件开发速查表新手速成手册
前端·javascript·typescript
AnalogElectronic14 小时前
uniapp学习6,滚动字幕播报
javascript·学习·uni-app
全马必破三14 小时前
Vue3+Node.js 实现AI流式输出全解析
前端·javascript·node.js
计算机学姐14 小时前
基于SpringBoot的奶茶店点餐系统【协同过滤推荐算法+数据可视化统计】
java·vue.js·spring boot·mysql·信息可视化·tomcat·推荐算法
Yupureki14 小时前
《Linux系统编程》19.线程同步与互斥
java·linux·服务器·c语言·开发语言·数据结构·c++