使用 vue2-editor 遇到的问题
自定义图片上传
vue2-editor
是个不错的富文本编辑器,但是美中不足的是他把图片全部作为 BASE64 上传了,但我们一般是存 URL,这有利于数据库优化和异步加载,所以才自己包装了一下。
关于文件异步上传,可以看我另一篇文章:https://wolfx.cn/html5-file-api/
包装如下:
html
<template>
<div style="position: relative;">
<vue-editor
ref="editor"
:editor-toolbar="customToolbar"
:value="value"
@input="onChange"
:useCustomImageHandler="true"
@image-added="handleImageAdded"
></vue-editor>
<span v-if="limit > 0" class="count-div"> {{ count }}/{{ limit }} </span>
</div>
</template>
typescript
{
/**
* 自定义图片上传
* @param file
* @param Editor
* @param cursorLocation
* @param resetUploader
*/
handleImageAdded(file: File, Editor: Quill, cursorLocation: number, resetUploader: Function) {
if (!this.action) {
console.error("action 未设置");
return;
}
uploadAsync(file, {
uploadProgress: this.uploadProgress,
uploadComplete: (event: ProgressEvent<any>) => {
try {
const res = JSON.parse(event.target.responseText);
if (res.code === 200) {
if (Array.isArray(res.data) && res.data.length > 0) {
res.data.forEach((img: string) => {
Editor.insertEmbed(cursorLocation, "image", img);
});
} else if (typeof res.data === "string") {
Editor.insertEmbed(cursorLocation, "image", res.data);
}
resetUploader();
} else {
console.error(res.msg);
}
} catch (e) {
console.error("JSON解析异常");
}
},
uploadFailed: this.uploadFailed,
uploadCanceled: this.uploadCanceled,
});
},
}
参考文档:https://www.vue2editor.com/examples/#custom-image-handler
自定义插入元素(例子支持 section 元素的插入)
typescript
import Quill from "quill";
const Size = Quill.import("attributors/style/size");
const BlockEmbed = Quill.import("blots/block/embed");
export const fontSizeList = ["12px", "14px", "16px", "18px", "20px", "22px", "24px", "26px", "28px", "30px"];
Size.whitelist = fontSizeList;
Quill.register(Size, true);
// 自定义插入元素
class SectionEmbed extends BlockEmbed {
static create(value: string) {
const node = super.create(value);
node.setAttribute("contenteditable", "false");
node.setAttribute("width", "100%");
// 设置自定义html
node.innerHTML = this.transformValue(value);
return node;
}
static transformValue(value: string) {
let handleArr = value.split("\n");
handleArr = handleArr.map((e) => e.replace(/^[\s]+/, "").replace(/[\s]+$/, ""));
return handleArr.join("");
}
// 返回节点自身的value值 用于撤销操作
static value(node: Element) {
return node.innerHTML;
}
}
// blotName
SectionEmbed.blotName = "Section";
// class名将用于匹配blot名称
SectionEmbed.className = "embed-section";
// 标签类型自定义
SectionEmbed.tagName = "section";
Quill.register(SectionEmbed, true);
自定义支持 CTRL+V 插入图片
typescript
{
mounted() {
const $editor: any = this.$refs.editor;
this.handleImagePaste($editor.quill);
if (this.limit) {
this.applyLimit();
}
},
/**
* 自定义粘贴图片功能
* @param quill
*/
handleImagePaste(quill: Quill) {
quill.root.addEventListener(
"paste",
(evt: ClipboardEvent) => {
if (evt.clipboardData && evt.clipboardData.files && evt.clipboardData.files.length) {
evt.preventDefault();
for (let i = 0; i < evt.clipboardData.files.length; i++) {
const file = evt.clipboardData.files[i];
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return;
}
this.handleImageAdded(file, quill, quill.getSelection()?.index || 0, () => {});
}
}
},
false,
);
},
}