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

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

相关推荐
漂流瓶jz5 小时前
Webpack如何实现万物皆可import?loader的使用/配置/手写实践
前端·javascript·webpack
ZC跨境爬虫5 小时前
跟着 MDN 学CSS day_41:显式轨道、隐式网格与区域命名放置
前端·javascript·css·ui·交互
稳联技术老娜5 小时前
DeviceNet主站怎么连接西门子PLC,Profinet网关配置手册(那智机器人)
服务器·网络·数据库
9分钟带帽6 小时前
linux_系统开机自动执行shell脚本
linux·服务器
修己xj6 小时前
告别手动存图!这款叫 Fatkun 的浏览器插件,简直是素材收集神器
前端
袋鼠云数栈7 小时前
从前端到基础设施,ACOS 如何打通企业全链路可观测
运维·前端·人工智能·数据治理·数据智能
AskHarries7 小时前
系统提示词、开发者指令和用户输入的优先级
java·前端·数据库
Moment7 小时前
长上下文会最终杀死 Rag 吗?
前端·javascript·后端
消失在人海中7 小时前
oracle 数据库多表关联查询
服务器·数据库·oracle
qcx237 小时前
【系统学AI】25 论文导读 ①:两篇改变 AI 的开山之作——Attention Is All You Need & ReAct
前端·人工智能·react.js·transformer