Quill 富文本编辑器自行实现监听粘贴事件,并自定义粘贴图片上传(vue3)
## 简介 使用富文本编辑器时,我们一般期望可以自定义图片上传,在 `Quill` 中,粘贴图片时默
渲染中...
## 简介
使用富文本编辑器时,我们一般期望可以自定义图片上传,在 `Quill` 中,粘贴图片时默认是将图片转为 `base64`文本的形式,存储在正文正,这显然不是我们想要的效果。
想要自定义 `Quill` 的图片粘贴上传,而不是转为 `base64`,需要自行覆盖编辑器的粘贴事件,然后自行实现图片上传与回显的逻辑,本文就以一个简单的示例来演示如何实现这个功能。
> Quill是一款流行的开源富文本编辑器,官网地址:https://quilljs.com/
<!-- more -->
## 粘贴图片上传
### 1.拦截粘贴图片事件
```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
### 2.监听编辑器粘贴事件
```ts
quill.root.addEventListener("paste", (e) => {
// 调用自定义的粘贴事件处理器
overwriteParseImage(e, quill);
});
```
### 3.自定义粘贴事件处理器
```ts
const 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` 上传图片的基本步骤:
1. 覆盖 `toolbar` 选择图片功能;
2. 自行实现选择图片功能;
3. 自行实现图片上传与回显逻辑。
### 1.覆盖 `toolbar` 选择图片功能
```ts
// 获取 quill 编辑器的toolbar【quill对象为上面提到的初始化的富文本编辑器】
const toolbar = quill.getModule("toolbar");
// 将图片功能指向自定义的选择图片事件
// @ts-ignore
toolbar.addHandler("image", selectLocalImage);
```
### 2.自行时间隐藏式的选择图片功能
```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);
});
};
```
### 3.自定义上传图片功能
```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;
}
```
这种方案虽然实现了图片居中,但靠右就不太好实现了,不知道你有没有什么好方法?欢迎评论解答!!!
## 赞助请求
**建站因为热爱,生活需要Money,本站非常需要屏幕前的大佬动动您发财的小手,点击一次以示鼓励,祝您生活愉快!**
<!-- 文章内嵌广告位 -->
<div class="article-ads"></div>
> PS:如果看不到广告,可能是网络原因或被拦截了。再次祝您生活愉快~~ 🥰END
评论
登录后查看和发表评论
前往登录