使用富文本编辑器时,我们一般期望可以自定义图片上传,在 Quill
中,粘贴图片时默认是将图片转为 base64
文本的形式,存储在正文正,这显然不是我们想要的效果。
想要自定义 Quill
的图片粘贴上传,而不是转为 base64
,需要自行覆盖编辑器的粘贴事件,然后自行实现图片上传与回显的逻辑,本文就以一个简单的示例来演示如何实现这个功能。
Quill是一款流行的开源富文本编辑器,官网地址:https://quilljs.com/
ts // 初始化富文本编辑框【提示:vue3的setup语法糖写法,请在onMounted中初始化quill编辑器】
const quill = new Quill("#editor", options);
// img粘贴事件拦截
quill.clipboard.addMatcher("img", (node, delta) => {
return delta; // 阻止 Quill 默认的图片插入行为(这里没有阻止,是为了防止图片上传失败时,仍然保持base64图片可见)
});
PS:
quill.clipboard.addMatcher("img")
在最新版Quill中(2.0.2
),不起作用,因此拦截实际没有生效。详见:https://github.com/slab/quill/issues/4337
ts quill.root.addEventListener("paste", (e) => {
// 调用自定义的粘贴事件处理器
overwriteParseImage(e, quill);
});
tsconst overwriteParseImage = (e: ClipboardEvent, q: Quill) => {
// 判断如果粘贴内容不为空,并且粘贴的是特殊元素或文件,则执行自定义逻辑
if (e.clipboardData && (e.clipboardData.items || e.clipboardData.files)) {
const items = e.clipboardData.items || e.clipboardData.files;
// 图片格式正则,自行修改!!!
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
// 阻止默认行为
e.stopPropagation();
e.preventDefault();
// 遍历上传图片(图片可能是多张)
for (let i = 0; i < items.length; i++) {
if (IMAGE_MIME_REGEX.test(items[i].type)) {
const file = items[i].getAsFile() ? items[i].getAsFile() : items[i];
if (file) {
const formData = new FormData();
// @ts-ignore
formData.append("file", file);
// uploadPublicFile 为自定义图片上传方法,不做展示,根据自己业务实现即可
uploadPublicFile(formData).then((res) => {
const range = q.getSelection(); // 获取当前光标位置
if (range && res.c == 200) {
// 图片上传成功后,删除原base64图片,替换为上传成功后的图片url【这部分逻辑请根据自己业务实现】
q.deleteText(range.index - 2, 2, "user"); // 删除图片占位符
q.insertEmbed(range.index, "image", res.d?.fileUrl); // 插入上传后的图片 URL
}
});
}
}
}
}
};
除了粘贴事件自定义上传图片外,Quill
编辑器也有自己的上传图片 toolbar
,为何更好的使用体验,我们还要在 toolbar
选择图片时改为上传图片。
要想实现 toolbar
选择图片时改为上传图片,与粘贴图片该为上传图片的逻辑是类似的,只不过代码写法有所不同,自定义 toolbar
上传图片的基本步骤:
toolbar
选择图片功能;toolbar
选择图片功能ts // 获取 quill 编辑器的toolbar【quill对象为上面提到的初始化的富文本编辑器】
const toolbar = quill.getModule("toolbar");
// 将图片功能指向自定义的选择图片事件
// @ts-ignore
toolbar.addHandler("image", selectLocalImage);
ts// 图片选择器【一个隐藏的html-input元素】
const quillImageSelect = ref();
const selectLocalImage = () => {
// 初始化图片选择输入框
quillImageSelect.value = document.createElement("input");
quillImageSelect.value.setAttribute("type", "file");
quillImageSelect.value.setAttribute("accept", "image/*");
quillImageSelect.value.setAttribute("style", "visibility:hidden"); // 设置为隐藏
// 自定义的图片上传功能绑定onchange事件【quillImageUpload为自定义功能函数】
quillImageSelect.value.onchange = quillImageUpload.bind(
quillImageSelect.value
);
document.body.appendChild(quillImageSelect.value);
quillImageSelect.value.click(); // 模拟点击事件,自动开始图片选择上传
window.requestAnimationFrame(() => {
document.body.removeChild(quillImageSelect.value);
});
};
ts// 函数包装一层,便于绑定
const quillImageUpload = () => {
imageUpload(quill);
};
// 真正的图片上传功能函数【一次只能选择一张图片】
const imageUpload = (q: Quill) => {
const file = quillImageSelect.value.files[0];
const fileReader = new FileReader();
if (file) {
fileReader.readAsDataURL(file);
}
const formData = new FormData();
formData.append("file", file);
// uploadPublicFile 为自定义图片上传功能代码,请根据自身业务实现即可
uploadPublicFile(formData).then((res) => {
// console.log(res);
const range = q.getSelection(); // 获取当前光标位置
if (range && res.c == 200) {
// 删除base64图片,与粘贴事件处理一致,请基于自己业务自行修改
q.deleteText(range.index, 1); // 删除图片占位符
q.insertEmbed(range.index, "image", res.d?.fileUrl); // 插入上传后的图片 URL
}
});
};
Quill无疑是一款好用的开源服务本编辑器,但对于自定义图片上传还是不太适配,很多需要自行实现的逻辑,不知道后面会不会优化这个功能?
PS:有一个问题,Quill编辑器采用的居中实现方案是class="text-center"
,即text-align:center;
,这种方案可能适用于 base64
格式的图片,但由于我们自定义图片上传后,图片实际显示的是 img
标签,所以这种居中方案不再适用于图片,因此我们需要自行覆盖一下这个居中实现方案,目前我采用的是 margin
方案,即:
css.text-center img {
margin: 0 auto;
}
这种方案虽然实现了图片居中,但靠右就不太好实现了,不知道你有没有什么好方法?欢迎评论解答!!!
本文作者:DingDangDog
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!