1、前言
富文本编辑器上传图片默认为base64,存入数据库过于庞大,由于若依以及quill-editor不支持粘贴图片上传, 因此加入了监听 paste 方法 实现图片地址上传,并替换到富文本编辑器中
2、核心代码实现
let quill = quillEditorRef.value.getQuill();
let toolbar = quill.getModule("toolbar");
// 粘贴事件
quill.root.addEventListener("paste", (evt) => {
if (!props.isPasteUpload) {
return
}
let rtf;
let videoType = /^video\/.*/;
if (evt.clipboardData.files.length > 0) {
rtf = evt.clipboardData.files[0];
if (videoType.test(rtf.type)) {
} else {
proxy.$refs.editorUploadRef.handleStart(rtf);
fileNum.value = 1;
}
// let file = base64toFile(`data:image/png;base64,${rtf}`)
} else {
rtf = evt.clipboardData.getData('text/rtf');
// 提取图片信息
const hexStrings = extractImageDataFromRtf(rtf);
// 获取base64图片数据
const base64Images = hexStrings.map((hexObj) => {
return convertHexToBase64(hexObj.hex);
})
const fileList = [];
// 调用上传接口
for (let i = 0; i < base64Images.length; i++) {
let file = base64toFile(`data:image/png;base64,${base64Images[i]}`)
proxy.$refs.editorUploadRef.handleStart(file);
fileList.push(file)
}
fileNum.value = fileList.length;
}
isFile.value = true;
// proxy.$refs.editorUploadRef.handleStart(fileList);
if (videoType.test(rtf.type)) {
proxy.$message.error("暂不支持粘贴视频!");
} else {
proxy.$refs.editorUploadRef.submit();
}
})
// 将base64转file
const base64toFile = (dataurl, filename = 'file') => {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let suffix = mime.split('/')[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
let file = new File([u8arr], `${filename}.${suffix}`, {
type: mime
})
return file
}
// 将hex格式转化为base64
const convertHexToBase64 = (hexString) => {
return btoa(hexString.match(/\w{2}/g).map(char => {
return String.fromCharCode(parseInt(char, 16));
}).join(''));
}
/**
*
* rtf中提取图片信息
* 利用正则从rtf内容中提取到图片的核心信息,得到数组。其中数组中保存的信息有
{
type: ‘’, //图片类型
hex: ‘’ // hex字符串
}
* @param {*} rtfData
*/
const extractImageDataFromRtf = (rtfData) => {
if (!rtfData) {
return [];
}
const regexPictureHeader = /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/
const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}', 'g');
const images = rtfData.match(regexPicture);
const result = [];
if (images) {
for (const image of images) {
let imageType = false;
if (image.includes('\\pngblip')) {
imageType = 'image/png';
} else if (image.includes('\\jpegblip')) {
imageType = 'image/jpeg';
}
if (imageType) {
result.push({
hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
type: imageType
});
}
}
}
return result;
}
// 上传成功处理
function handleUploadSuccess(res, file) {
// 如果上传成功
if (res.code == 200) {
// 获取富文本实例
let quill = toRaw(quillEditorRef.value).getQuill();
// 获取光标位置
let length = quill.selection.savedRange.index;
if (isFile.value) {
pasteFileList.value.push(res.fileName)
if (pasteFileList.value.length == fileNum.value) {
setResponseUrl();
quill.setSelection(length + 1);
}
} else {
// 插入图片,res.url为服务器返回的图片链接地址
quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName);
// 调整光标到最后
quill.setSelection(length + 1);
}
} else {
proxy.$modal.msgError("图片插入失败");
}
}
// 粘贴图片插入
const setResponseUrl = () => {
const editorDom = proxy.$refs.quillEditorRef.getQuill().root;
const editorImgs = editorDom.querySelectorAll('img[src*="//:0"]');
// const editorImgs = editorDom.querySelectorAll('img');
// 替换图片Url
editorImgs.forEach((item, index) => {
item.src = import.meta.env.VITE_APP_BASE_API + pasteFileList.value[index];
})
isFile.value = false;
fileNum.value = 0;
pasteFileList.value = [];
}
3、代码解释
上传逻辑不再追述,这里只做了粘贴图片上传的相关代码逻辑。其他请自行修改。