上一篇,我们实现了剪贴板粘贴图片并上传至服务器的功能,在本篇,我们实现从外部拖拽图片到编辑器中,也可以将图片上传到服务器。
功能实现:
新增一个 handleDrop 方法,在这个方法中处理拖拽及上传方法的触发。
需要注意的是,我们需要 阻止浏览器默认拖拽行为(否则可能打开图片):
javascript
editorRef.value.addEventListener('dragover', (e) => {
e.preventDefault()
})
下面直接来看完整代码:
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.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
}
}
}
const handleDrop = async (e) => {
const files = e.dataTransfer?.files
if (!files || files.length === 0) return
const imageFiles = Array.from(files).filter(f => f.type.startsWith('image/'))
if (imageFiles.length === 0) return
e.preventDefault()
e.stopPropagation()
let index = 0
try {
const range = editorInstance.getSelection(true)
index = range ? range.index : 0
} catch {
index = 0
}
for (const file of imageFiles) {
try {
const url = await uploadImage(file)
editorInstance.insertEmbed(index, 'image', url)
index += 1
} catch (err) {
console.error('拖拽上传失败', err)
}
}
}
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)
editorRef.value.addEventListener('drop', handleDrop, true)
editorRef.value.addEventListener('dragover', (e) => {
e.preventDefault()
})
})
</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>
关于编辑器中直接上传图片的处理场景已经介绍的差不多了,下一篇我们来看看假如我从外部(网页、Word 文档)粘贴了一篇文章,里面包含图片、文本 等复杂场景,要如何处理呢?