wangeditor
wangeditor
下载
pnpm add @wangeditor/editorpnpm add @wangeditor/editor-for-vue@next
mode: ‘default’ 默认模式 - 集成了 wangEditor 所有功能
mode: ‘simple’ 简洁模式 - 仅有部分常见功能,但更加简洁易用
基础结构
<script lang="ts" setup>
import "@wangeditor/editor/dist/css/style.css"; // 引入 cssimport { onBeforeUnmount, ref, shallowRef } from "vue";import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { IToolbarConfig, IEditorConfig, IDomEditor } from "@wangeditor/editor";// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef();// 模式
const mode = ref("default");/* 工具栏配置 */
const toolbarConfig: Partial<IToolbarConfig> = {};// 编辑器配置
const editorConfig: Partial<IEditorConfig> = { placeholder: "请输入内容..." };// 内容 HTML
const valueHtml = ref("");function handleCreated(editor: IDomEditor) {// 记录 editor 实例,重要!editorRef.value = editor;
}// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {const editor = editorRef.value;if (editor == null) return;editor.destroy();
});
</script><template><div style="border: 1px solid #ccc"><Toolbarstyle="border-bottom: 1px solid #ccc":editor="editorRef":defaultConfig="toolbarConfig":mode="mode"/><Editorstyle="height: 500px; overflow-y: hidden"v-model="valueHtml":defaultConfig="editorConfig":mode="mode"@onCreated="handleCreated"/></div>
</template>
工具栏配置
/* 工具栏配置 */
const toolbarConfig: Partial<IToolbarConfig> = {// 排除的菜单选项excludeKeys: ["insertTable","insertImage", // 排除菜单组 写菜单组 key 的值即可,如排除图片中的 网络图片选项 key("insertImage")],
};
获取菜单选项列表 toolbar
setTimeout 以便获取值 toolbar
import { IToolbarConfig, IEditorConfig, IDomEditor, DomEditor } from "@wangeditor/editor";function handleCreated(editor: IDomEditor) {setTimeout(() => {const toolbar = DomEditor.getToolbar(editor);const toolbarKeys = toolbar?.getConfig().toolbarKeys;console.log("toolbarKeys", toolbarKeys);}, 0);
}
编辑器配置
编辑器配置中 onXxx 格式的生命周期函数,必须通过 Vue 事件来传递,不可以放在 editorConfig 中
编辑器内容、选区变化时的回调函数。
<template><Editor@onChange="handleChange"/>
</template>
<script lang="ts" setup>function handleChange(editor: IDomEditor) {console.log("content", editor.children);}
</script>
菜单配置
菜单配置是工具栏的菜单项的详细配置,该配置也在编辑器配置下
获取菜单所有 key
function handleCreated(editor: IDomEditor) {editor.getAllMenuKeys();
}
获取某菜单默认配置 --> 获取图片默认配置
function handleCreated(editor: IDomEditor) {const uploadImage = editor.getMenuConfig("uploadImage");console.log("uploadImage", uploadImage);
}
修改配置 --> 修改颜色
// 编辑器配置
const editorConfig: Partial<IEditorConfig> = {placeholder: "请输入内容...",autoFocus: false,// 修改配置MENU_CONF: {// 颜色color: {colors: ["#000", "#333", "#666"],},},
};// 单独拿出来配置,结果与上面一样
editorConfig.MENU_CONF["color"] = {colors: ["#000", "#333", "#666"],
};
上传图片
基本上传
const editorConfig: Partial<IEditorConfig> = {MENU_CONF: {// 上传图片的配置uploadImage: {// 必填 请求地址server: "/api/file",// file 文件的字段名fieldName: "file",// 其他传递的参数, 加在 formData 中meta: {scene: "avatar",},// 请求头:存放 tokenheaders: {Authorization: " ",},// 单个文件的最大体积限制,默认为 2MmaxFileSize: 1 * 1024 * 1024, // 1M// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []allowedFileTypes: ["image/*"],// 上传前的回调onBeforeUpload(file: File) {console.log("上传前的回调", file);// return file;},// 上传成功onSuccess(file: File, res: any) {console.log(` 上传成功`, res);},// 单个文件上传失败onFailed(file: File, res: any) {console.log(` 上传失败`, res);},// 上传错误,或者触发 timeout 超时onError(file: File, err: any, res: any) {console.log(`传出错`, err);console.log(`上传出错`, res);},},},
};
服务端 response body 无法按照上述格式,可以使用下文的 customInsert
/*** 从 res 中找到 url alt href ,然后插入图片* "url": "xxx", // 图片 src ,必须* "alt": "yyy", // 图片描述文字,非必须* "href": "zzz" // 图片的链接,非必须*/type InsertFnType = (url: string, alt: string, href: string) => void;
const editorConfig: Partial<IEditorConfig> = {MENU_CONF: {// 自定义插入图片customInsert(res: any, insertFn: InsertFnType) {// res 即服务端的返回结果console.log("自定义插入图片", res);insertFn(res.data.url, "", "");},},
};
自定义上传图片逻辑
type InsertFnType = (url: string, alt: string, href: string) => void;
const editorConfig: Partial<IEditorConfig> = {MENU_CONF: {// 自定义上传async customUpload(file: File, insertFn: InsertFnType) {// file 即选中的文件console.log("自定义上传", file);// 自己实现上传,并得到图片 url alt hrefconst formData = new FormData();formData.append("file", file, file?.name);formData.append("scene", "avatar");// 上传接口const res = await upload(formData);// 最后插入图片insertFn(res.data.url, "", "");},},
};function checkImageSize(fileTypeList: string[] = ["image/jpeg", "image/jpg", "image/png"]) {const flag = fileTypeList.some((item) => file.type === item);if (!flag) return false;return true;
}
function checkImageType(size: number = 1024 * 1024 * 1) {if (file.size > size) return false;return true;
}