wangEditor 富文本详解

前言:wangEditor 官网 。本文档讲解 wangEditor 在 vue3 中的使用。

一:快速开始

1. 安装

需要安装 @wangeditor/editor、@wangeditor/editor-for-vue@next 两个依赖

# 安装 editor
npm install @wangeditor/editor
# or
yarn add @wangeditor/editor
# or
pnpm add @wangeditor/editor# 安装 Vue3 组件
npm install @wangeditor/editor-for-vue@next
# or
yarn add @wangeditor/editor-for-vue@next
# or
pnpm add @wangeditor/editor-for-vue@next

2. 构建组件 components/Rich.vue

<script setup lang="ts">import "@wangeditor/editor/dist/css/style.css"; // 引入 cssimport { onBeforeUnmount, ref, shallowRef, computed } from "vue";import { Editor, Toolbar } from "@wangeditor/editor-for-vue";const props = defineProps({modelValue: {type: String,required: true,},toolbarConfig: {type: Object,default: {},},editorConfig: {type: Object,default: {placeholder: "请输入内容...",},},height: {type: String,default: "300px",},});const emits = defineEmits(["update:modelValue"]);let valueHtml = computed({get() {return props.modelValue;},set(value) {emits("update:modelValue", value);},});let style: any = computed(() => {return {height: props.height,"overflow-y": "hidden",};});// 编辑器实例,必须用 shallowRefconst editorRef = shallowRef();// 模式let mode = ref("default");// 组件销毁时,也及时销毁编辑器onBeforeUnmount(() => {const editor = editorRef.value;if (editor == null) return;editor.destroy();});const handleCreated = (editor: any) => {editorRef.value = editor; // 记录 editor 实例,重要!};
</script><template><div class="editor-content-view"><Toolbarstyle="border-bottom: 1px solid #ccc":editor="editorRef":defaultConfig="toolbarConfig":mode="mode"/><Editor:style="style"v-model="valueHtml":defaultConfig="editorConfig":mode="mode"@onCreated="handleCreated"/></div>
</template><style lang="scss" scoped>.editor-content-view {border: 1px solid #ccc;z-index: 999;}
</style>

3. 使用 Rich.vue 组件

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");
</script><template><div class="page-rich"><Rich v-model="richHtml" /></div>
</template><style lang="scss" scoped></style>

二:优势

使用 slate.js(但不依赖 React)为内核、强稳定性、高扩展性、有详细中文文档、可直接使用无需二次开发、不依赖框架。

三:基础

1. 定义 CSS

可自定义编辑器、工具栏的尺寸、边框、z-index 等样式。

<template><!-- 边框 --><div class="editor-content-view"><!-- 工具栏 --><Toolbar style="border-bottom: 1px solid #ccc" /><!-- 编译器 --><Editor style="height: 500px; overflow-y: hidden" /></div>
</template><style lang="scss" scoped>.editor-content-view {border: 1px solid #ccc;z-index: 999;}
</style>

2. 定义 HTML

如果想要“全屏”功能,则要求工具栏、编辑器 DOM 节点必须是同一层级,同时父级盒子设置 z-index: 999。

<template><div class="editor-content-view"><!-- 工具栏 --><Toolbar /><!-- 编译器 --><Editor /></div>
</template><style lang="scss" scoped>.editor-content-view {z-index: 999;}
</style>

3. 模式

通过设置 mode 改变富文本模式,'default' 默认模式,基础所有功能。'simple' 简洁模式,仅有常用功能。

<script setup lang="ts">// 模式let mode = ref("default");
</script><template><div class="editor-content-view"><Toolbar :mode="mode" /><Editor :mode="mode" /></div>
</template>

四:在 vue3 中使用

1. 配置

可通过 toolbarConfig editorConfig 来修改菜单栏和编辑器的配置。注意:编辑器配置中 onXxx 格式的生命周期函数,必须通过 Vue 事件来传递,不可以放在 editorConfig 中

<script setup lang="ts">const props = defineProps({toolbarConfig: {type: Object,default: {},},editorConfig: {type: Object,default: {placeholder: "请输入内容...",},},});const handleCreated = (editor: any) => {editorRef.value = editor; // 记录 editor 实例,重要!};
</script><template><div class="editor-content-view"><Toolbar :defaultConfig="toolbarConfig" /><Editor :defaultConfig="editorConfig" @onCreated="handleCreated" /></div>
</template><style lang="scss" scoped>.editor-content-view {border: 1px solid #ccc;z-index: 999;}
</style>

2. 调用 API

当编辑器渲染完成之后,通过 editorRef.value 获取 editor 实例,即可调用它的 API 。

// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {const editor = editorRef.value;if (editor == null) return;editor.destroy();
});

五:配置和 API

下面代码例子,都是以 components/Rich.vue 作为例子的基础上扩展功能。

1. 工具栏配置

1.1 getConfig

通过 toolbar.getConfig() 查看工具栏的默认配置

import { DomEditor } from "@wangeditor/editor";const handleCreated = (editor) => {const toolbar = DomEditor.getToolbar(editor);const result = toolbar.getConfig();console.log(result);
};

1.2 toolbarKeys

重新配置工具栏,显示哪些菜单,以及菜单的排序、分组。可以通过 toolbar.getConfig().toolbarKeys 查看当前的默认配置。

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("asdf");let toolbarConfig = {toolbarKeys: [// 菜单 key"headerSelect",// 分割线"|",// 菜单 key"bold","italic",],insertKeys: {index: 1, // 插入的位置,基于当前的 toolbarKeyskeys: ["color", "bgColor"],},};
</script><template><div class="page-rich"><Rich v-model="richHtml" :toolbarConfig="toolbarConfig" /></div>
</template>

1.3 insertKeys

在当前 toolbarKeys 的基础上继续插入新菜单,如自定义扩展的菜单。

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("asdf");let toolbarConfig = {toolbarKeys: [// 菜单 key"headerSelect",// 分割线"|",// 菜单 key"bold","italic",],insertKeys: {index: 1, // 插入的位置,基于当前的 toolbarKeyskeys: ["color", "bgColor"],},};
</script><template><div class="page-rich"><Rich v-model="richHtml" :toolbarConfig="toolbarConfig" /></div>
</template>

1.4 excludeKeys

排除掉某些菜单

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("asdf");let toolbarConfig = {toolbarKeys: [// 菜单 key"headerSelect",// 分割线"|",// 菜单 key"bold","italic",],insertKeys: {index: 1, // 插入的位置,基于当前的 toolbarKeyskeys: ["color", "bgColor"],},excludeKeys: ["headerSelect"],};
</script><template><div class="page-rich"><Rich v-model="richHtml" :toolbarConfig="toolbarConfig" /></div>
</template>

2. 编辑器配置

2.1 getConfig

通过 editor.getConfig() 查看工具栏的默认配置

const handleCreated = (editor) => {const result = editor.getConfig();console.log(result);
};

2.2 editorConfig 配置

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({placeholder: "请输入",readOnly: false, // 是否只读,默认 falseautoFocus: true, // 是否focus, 默认 truescroll: true, // 是否支持滚动,默认true。不要固定 editor-container 的高度,设置一个 min-height 即可。maxLength: 20, // 最高内容长度,onMaxLength 当达到限制时,触发函数});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

2.3 编译器方法

<script setup lang="ts">// 编辑器创建完毕时的回调函数。const handleCreated = (editor) => {editorRef.value = editor;console.log("created", editor);};// 编辑器内容、选区变化时的回调函数。const handleChange = (editor) => {console.log("change:", editor.children);};// 编辑器销毁时的回调函数。调用 editor.destroy() 即可销毁编辑器const handleDestroyed = (editor) => {console.log("destroyed", editor);};// 编辑器 focus 时的回调函数。const handleFocus = (editor) => {console.log("focus", editor);};// 编辑器 blur 时的回调函数。const handleBlur = (editor) => {console.log("blur", editor);};// 自定义编辑器 alert 。const customAlert = (info, type) => {alert(`【自定义提示】${type} - ${info}`);};// 自定义粘贴。可阻止编辑器的默认粘贴,实现自己的粘贴逻辑。const customPaste = (editor, event, callback) => {console.log("ClipboardEvent 粘贴事件对象", event);// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html// const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)// 自定义插入内容editor.insertText("xxx");// 返回 false ,阻止默认粘贴行为event.preventDefault();callback(false); // 返回值(注意,vue 事件的返回值,不能用 return)// 返回 true ,继续默认的粘贴行为// callback(true)};
</script><template><div class="editor-content-view"><Toolbar /><Editor@onCreated="handleCreated"@onChange="handleChange"@onDestroyed="handleDestroyed"@onFocus="handleFocus"@onBlur="handleBlur"@customAlert="customAlert"@customPaste="customPaste"/></div>
</template>

3. 菜单配置

各个菜单项的详细配置。

3.1 通用方法

要配置哪个菜单,首先要知道这个菜单的 key 。执行 editor.getAllMenuKeys() 可获取编辑器所有菜单,从中找到自己想要的菜单 key 即可。

const handleCreated = (editor) => {const result = editor.getAllMenuKeys();console.log(result);
};

找到菜单 key 之后,可以先看看菜单的当前配置,再自行修改。

const handleCreated = (editor) => {const result = editor.getMenuConfig("uploadImage"); // 获取 uploadImage 的当前配置console.log(result);
};

3.2 颜色

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({MENU_CONF: {color: {colors: ["#000", "#333", "#666"],},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.3 字号

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({MENU_CONF: {fontSize: {fontSizeList: [// 元素支持两种形式//   1. 字符串;//   2. { name: 'xxx', value: 'xxx' }"12px","16px",{ name: "24px", value: "24px" },"40px",],},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.4 字体

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({MENU_CONF: {fontFamily: {fontFamilyList: [// 元素支持两种形式//   1. 字符串;//   2. { name: 'xxx', value: 'xxx' }"黑体","楷体",{ name: "仿宋", value: "仿宋" },"Arial","Tahoma","Verdana",],},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.5 行高

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({MENU_CONF: {lineHeight: {lineHeightList: ["1", "1.5", "2", "2.5"],},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.6 表情

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");let editorConfig = ref({MENU_CONF: {emotion: {emotions: "😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉".split(" "),},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.7 链接

checkLink 校验链接、parseLinkUrl 转换链接 url

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");// 自定义校验链接const customCheckLinkFn = (text, url) => {if (!url) {return;}if (url.indexOf("http") !== 0) {return "链接必须以 http/https 开头";}return true;// 返回值有三种选择:// 1. 返回 true ,说明检查通过,编辑器将正常插入链接// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息};// 自定义转换链接 urlconst customParseLinkUrl = (url) => {if (url.indexOf("http") !== 0) {return `http://${url}`;}return url;};let editorConfig = ref({MENU_CONF: {insertLink: {checkLink: customCheckLinkFn, // 也支持 async 函数parseLinkUrl: customParseLinkUrl, // 也支持 async 函数},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.8 图片

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");// 自定义校验图片const customCheckImageFn = (src, alt, url) => {if (!src) {return;}if (src.indexOf("http") !== 0) {return "图片网址必须以 http/https 开头";}return true;// 返回值有三种选择:// 1. 返回 true ,说明检查通过,编辑器将正常插入图片// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息};// 转换图片链接const customParseImageSrc = (src) => {if (src.indexOf("http") !== 0) {return `http://${src}`;}return src;};let editorConfig = ref({MENU_CONF: {// 插入图片insertImage: {onInsertedImage(imageNode) {if (imageNode == null) return;const { src, alt, url, href } = imageNode;console.log("inserted image", src, alt, url, href);},checkImage: customCheckImageFn, // 也支持 async 函数parseImageSrc: customParseImageSrc, // 也支持 async 函数},// 编辑图片editImage: {onUpdatedImage(imageNode) {if (imageNode == null) return;const { src, alt, url } = imageNode;console.log("updated image", src, alt, url);},checkImage: customCheckImageFn, // 也支持 async 函数parseImageSrc: customParseImageSrc, // 也支持 async 函数},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.9 上传图片

3.9.1 服务端地址

必填,否则上传图片会报错。

let editorConfig = ref({MENU_CONF: {uploadImage: {server: "/api/upload",},},
});

正常情况要求服务端返回体如下,如果不满足可以查看自定义插入。

// 上传成功返回
{"errno": 0, // 注意:值是数字,不能是字符串"data": {"url": "xxx", // 图片 src ,必须"alt": "yyy", // 图片描述文字,非必须"href": "zzz" // 图片的链接,非必须}
}// 上传失败返回
{"errno": 1, // 只要不等于 0 就行"message": "失败信息"
}
3.9.2 基本配置
let editorConfig = ref({MENU_CONF: {uploadImage: {// form-data fieldName ,默认值 'wangeditor-uploaded-image'fieldName: "your-custom-name",// 单个文件的最大体积限制,默认为 2MmaxFileSize: 1 * 1024 * 1024, // 1M// 最多可上传几个文件,默认为 100maxNumberOfFiles: 10,// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []allowedFileTypes: ["image/*"],// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。meta: {token: "xxx",otherKey: "yyy",},// 将 meta 拼接到 url 参数中,默认 falsemetaWithUrl: false,// 自定义增加 http  headerheaders: {Accept: "text/x-json",otherKey: "xxx",},// 跨域是否传递 cookie ,默认为 falsewithCredentials: true,// 超时时间,默认为 10 秒timeout: 5 * 1000, // 5 秒},},
});
3.9.3 回调函数
let editorConfig = ref({MENU_CONF: {uploadImage: {// 上传之前触发onBeforeUpload(file) {// file 选中的文件,格式如 { key: file }return file;// 可以 return// 1. return file 或者 new 一个 file ,接下来将上传// 2. return false ,不上传这个 file},// 上传进度的回调函数onProgress(progress) {// progress 是 0-100 的数字console.log("progress", progress);},// 单个文件上传成功之后onSuccess(file, res) {console.log(`${file.name} 上传成功`, res);},// 单个文件上传失败onFailed(file, res) {console.log(`${file.name} 上传失败`, res);},// 上传错误,或者触发 timeout 超时onError(file, err, res) {console.log(`${file.name} 上传出错`, err, res);},},},
});
3.9.4 自定义插入

如果服务端的返回体,不满足所需格式,可以使用 customInsert 自定义插入。

let editorConfig = ref({MENU_CONF: {uploadImage: {customInsert(res, insertFn) {// res 即服务端的返回结果// 从 res 中找到 url alt href ,然后插入图片insertFn(url, alt, href);},},},
});
3.9.5 自定义上传

如果不想使用 wangEditor 自带的上传功能,例如你要上传到阿里云 OSS 。可以通过 customUpload 来自定义上传。

let editorConfig = ref({MENU_CONF: {uploadImage: {async customUpload(file, insertFn) {// file 即选中的文件// 自己实现上传,并得到图片 url alt href// 最后插入图片insertFn(url, alt, href);},},},
});
3.9.6 自定义选择图片

如果不想使用 wangEditor 自带的选择文件功能,例如你有自己的图床,或者图片选择器。可以通过 customBrowseAndUpload 来自己实现选择图片、上传图片,并插入图片。

let editorConfig = ref({MENU_CONF: {uploadImage: {customBrowseAndUpload(insertFn) {// 自己选择文件// 自己上传文件,并得到图片 url alt href// 最后插入图片insertFn(url, alt, href);},},},
});
3.9.7 base64 插入图片
let editorConfig = ref({MENU_CONF: {uploadImage: {// 小于该值就插入 base64 格式(而不上传),默认为 0base64LimitSize: 5 * 1024, // 5kb},},
});

3.10 视频

onInsertedVideo 插入视频之后的回调、checkVideo 校验视频链接、parseVideoSrc 转换视频链接

<script setup lang="ts">import { ref } from "vue";import Rich from "@/components/Rich.vue";let richHtml = ref("");// 自定义校验视频const customCheckVideoFn = (src, poster) => {if (!src) {return;}if (src.indexOf("http") !== 0) {return "视频地址必须以 http/https 开头";}return true;// 返回值有三种选择:// 1. 返回 true ,说明检查通过,编辑器将正常插入视频// 2. 返回一个字符串,说明检查未通过,编辑器会阻止插入。会 alert 出错误信息(即返回的字符串)// 3. 返回 undefined(即没有任何返回),说明检查未通过,编辑器会阻止插入。但不会提示任何信息};// 自定义转换视频const customParseVideoSrc = (src) => {if (src.includes(".bilibili.com")) {// 转换 bilibili url 为 iframe (仅作为示例,不保证代码正确和完整)const arr = location.pathname.split("/");const vid = arr[arr.length - 1];return `<iframe src="//player.bilibili.com/player.html?bvid=${vid}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>`;}return src;};let editorConfig = ref({MENU_CONF: {insertVideo: {onInsertedVideo(videoNode) {if (videoNode == null) return;const { src } = videoNode;console.log("inserted video", src);},checkVideo: customCheckVideoFn, // 也支持 async 函数parseVideoSrc: customParseVideoSrc, // 也支持 async 函数},},});
</script><template><div class="page-rich"><Rich v-model="richHtml" :editorConfig="editorConfig" /></div>
</template>

3.11 上传视频

3.11.1 服务端地址

必填,否则上传图片会报错。

let editorConfig = ref({MENU_CONF: {uploadVideo: {server: "/api/upload",},},
});

正常情况要求服务端返回体如下,如果不满足可以查看自定义插入。

// 上传成功返回
{"errno": 0, // 注意:值是数字,不能是字符串"data": {"url": "xxx", // 视频 src ,必须"poster": "xxx.png" // 视频封面图片 url ,可选}
}// 上传失败返回
{"errno": 1, // 只要不等于 0 就行"message": "失败信息"
}
3.11.2 基本配置
let editorConfig = ref({MENU_CONF: {uploadVideo: {// form-data fieldName ,默认值 'wangeditor-uploaded-video'fieldName: "your-custom-name",// 单个文件的最大体积限制,默认为 10MmaxFileSize: 5 * 1024 * 1024, // 5M// 最多可上传几个文件,默认为 5maxNumberOfFiles: 3,// 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []allowedFileTypes: ["video/*"],// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。meta: {token: "xxx",otherKey: "yyy",},// 将 meta 拼接到 url 参数中,默认 falsemetaWithUrl: false,// 自定义增加 http  headerheaders: {Accept: "text/x-json",otherKey: "xxx",},// 跨域是否传递 cookie ,默认为 falsewithCredentials: true,// 超时时间,默认为 30 秒timeout: 15 * 1000, // 15 秒},},
});
3.11.3 回调函数
let editorConfig = ref({MENU_CONF: {uploadVideo: {// 上传之前触发onBeforeUpload(file) {// file 选中的文件,格式如 { key: file }return file;// 可以 return// 1. return file 或者 new 一个 file ,接下来将上传// 2. return false ,不上传这个 file},// 上传进度的回调函数onProgress(progress) {// progress 是 0-100 的数字console.log("progress", progress);},// 单个文件上传成功之后onSuccess(file, res) {console.log(`${file.name} 上传成功`, res);},// 单个文件上传失败onFailed(file, res) {console.log(`${file.name} 上传失败`, res);},// 上传错误,或者触发 timeout 超时onError(file, err, res) {console.log(`${file.name} 上传出错`, err, res);},},},
});
3.11.4 自定义插入

如果服务端的返回体,不满足所需格式,可以使用 customInsert 自定义插入。

let editorConfig = ref({MENU_CONF: {uploadVideo: {customInsert(res, insertFn) {// res 即服务端的返回结果// 从 res 中找到 url poster ,然后插入视频insertFn(url, poster);},},},
});
3.11.5 自定义上传

如果不想使用 wangEditor 自带的上传功能,例如你要上传到阿里云 OSS 。可以通过 customUpload 来自定义上传。

let editorConfig = ref({MENU_CONF: {uploadVideo: {async customUpload(file, insertFn) {// file 即选中的文件// 自己实现上传,并得到视频 url poster// 最后插入视频insertFn(url, poster);},},},
});
3.11.6 自定义选择视频

如果不想使用 wangEditor 自带的选择文件功能,例如你有自己的图床,或者视频文件选择器。可以通过 customBrowseAndUpload 来自己实现选择视频、上传视频,并插入视频

let editorConfig = ref({MENU_CONF: {uploadVideo: {customBrowseAndUpload(insertFn) {// 自己选择文件// 自己上传文件,并得到视频 url poster// 最后插入视频insertFn(url, poster);},},},
});

4. 编辑器 API

4.1 getConfig

获取编辑器所有配置

const handleCreated = (editor) => {const result = editor.getConfig();console.log(result);
};

4.2 getAllMenuKeys

获取编辑器所有 menu 的 key

const handleCreated = (editor) => {const result = editor.getAllMenuKeys();console.log(result);
};

4.3 getMenuConfig

获取单个 menu 的配置。

const handleCreated = (editor) => {const result = editor.getMenuConfig("color");console.log(result);
};

4.4 alert

编辑器 alert ,可通过 customAlert 配置。

editor.alert("错误信息", "error");

customAlert 配置

<script setup lang="ts">import { message } from "antd";const customAlert = (s, t) => {switch (t) {case "success":message.success(s);break;case "info":message.info(s);break;case "warning":message.warning(s);break;case "error":message.error(s);break;default:message.info(s);break;}};
</script><template><div class="editor-content-view"><Toolbar /><Editor @customAlert="customAlert" /></div>
</template>

4.5 handleTab

控制编辑器按 tab 键时,输入什么。

<script setup lang="ts">const handleCreated = (editor: any) => {editor.handleTab = () => editor.insertText("aaaaa");};
</script>
<template><div class="editor-content-view"><Toolbar /><Editor @onCreated="handleCreated" /></div>
</template>

4.6 getHtml

editor.getHtml() 获取非格式化的 html

const result = editor.getHtml();
console.log(result);

4.7 getText

获取当前编辑器的纯文本内容

const handleCreated = (editor) => {const result = editor.getText();console.log(result);
};

4.8 setHtml

重置编辑器的 HTML 内容。

editor.setHtml("<p>hello</p>");

4.9 isEmpty

判断当前编辑器内容是否为空(只有一个空段落)

editor.isEmpty();

4.10 getSelectionText

获取选中的文本

const result = editor.getSelectionText();
console.log(result);

4.11 getElemsByType

通过 type 获取编辑器的 element 列表。

editor.getElemsByType("image"); // 所有图片
editor.getElemsByType("link"); // 所有链接

4.12 getElemsByTypePrefix

通过 type 前缀获取编辑器的 element 列表。

editor.getElemsByTypePrefix("header"); // 获取所有标题 header1 header2 header3...

4.13 deleteBackward

向前删除,相当于按 backspace 键。

editor.deleteBackward();

4.14 deleteForward

向后删除,相当于按 delete 键

editor.deleteForward();

4.15 deleteFragment

删除选中的内容

editor.deleteFragment();

4.16 getFragment

获取选中的内容,json 格式

editor.getFragment();

4.17 insertBreak

在选区回车换行

editor.insertBreak();

4.18 insertText

在选区插入文本

editor.insertText("aaaa");

4.19 dangerouslyInsertHtml

插入富文本

editor.dangerouslyInsertHtml(`<h1>标题</h1><p>文本 <b>加粗</b></p>`);

4.20 clear

清空编辑器内容

editor.clear();

4.21 undo

撤销

editor.undo();

4.22 redo

重做

editor.redo();

4.23 insertNode

在选区插入一个节点

const node = { type: "paragraph", children: [{ text: "simple text" }] };
editor.insertNode(node);

4.24 insertNodes

在选区插入多个节点

import { SlateTransforms } from "@wangeditor/editor";const node1 = { type: "paragraph", children: [{ text: "aaa" }] };
const node2 = { type: "paragraph", children: [{ text: "bbb" }] };
const nodeList = [node1, node2];SlateTransforms.insertNodes(editor, nodeList);

4.25 removeNodes

删除选区所在的节点

import { SlateTransforms } from "@wangeditor/editor";SlateTransforms.removeNodes(editor);

4.26 获取选中节点

可使用 SlateEditor.nodes 获取选中的节点。

import { SlateEditor, SlateElement, SlateNode } from "@wangeditor/editor";const nodeEntries = SlateEditor.nodes(editor, {match: (node) => {if (SlateElement.isElement(node)) {if (node.type === "paragraph") {return true; // 匹配 paragraph}}return false;},universal: true,
});if (nodeEntries == null) {console.log("当前未选中的 paragraph");
} else {for (let nodeEntry of nodeEntries) {const [node, path] = nodeEntry;console.log("选中了 paragraph 节点", node);console.log("节点 path 是", path);}
}

4.27 setNodes

设置选中节点的属性

import { SlateTransforms } from "@wangeditor/editor";SlateTransforms.setNodes(editor,{// @ts-ignoretextAlign: "right",},{mode: "highest", // 针对最高层级的节点}
);

4.28 getParentNode

获取一个节点的父节点

const parentNode = editor.getParentNode(node); // 返回 node 或者 null

4.29 toDOMNode

获取一个节点对应的 DOM 节点

const elem = editor.toDOMNode(node); // 返回 HTMLElement

4.30 isInline

判断一个节点是否是 inline

const inline = editor.isInline(node);

4.31 isVoid

判断一个节点是否是 void

const void = editor.isVoid(node)

4.32 isText

判断一个节点是否是 text

import { SlateText } from "@wangeditor/editor";SlateText.isText(node); // true/false

4.33 isElement

判断一个节点是否是 elem

import { SlateElement } from "@wangeditor/editor";SlateElement.isElement(node); // true/false

4.34 addMark

为选中的文本添加标记(文本样式)

editor.addMark("bold", true); // 加粗
editor.addMark("color", "#999"); // 文本颜色

4.35 removeMark

对选中的文字,取消标记(文本样式)

editor.removeMark("bold"); // 取消加粗

4.36 marks

获取选中文字的标记(文本样式)

import { SlateEditor } from "@wangeditor/editor";SlateEditor.marks(editor); // 例如 { bold: true, color: "#595959" }

4.37 id

获取编辑器 id

editor.id; // 如 'wangEditor-1'

4.38 isFullScreen

编辑器是否全屏

editor.isFullScreen; // true/false

4.39 focus

聚焦到编辑器

editor.focus();// editor.focus(true) // 选区定位到最后

4.40 blur

失焦编辑器

editor.blur();

4.41 isFocused

判断当前编辑器是否聚焦?

editor.isFocused(); // true/false

4.42 updateView

强制更新视图

editor.updateView();

4.43 scrollToElem

滚动到指定元素,类似锚点。

editor.scrollToElem(elemId);

4.44 showProgressBar

显示进度条,一般用于上传功能

editor.showProgressBar(progress); // progress 为 0-100 的数字

4.45 hidePanelOrModal

隐藏当前的弹框 (如插入链接) 和下拉列表(如设置标题、设置字体)

editor.hidePanelOrModal();

4.46 fullScreen

设置为全屏

editor.fullScreen();

4.47 unFullScreen

取消全屏

editor.unFullScreen();

4.48 disable

禁用编辑器,设置为只读

editor.disable();

4.49 isDisabled

判断当前编辑器是否只读?

editor.isDisabled(); // true/false

4.50 enable

取消禁用,取消只读

editor.enable();

4.51 destroy

销毁编辑器和工具栏

editor.destroy();

4.52 getEditableContainer

获取编辑区域容器 DOM 节点

editor.getEditableContainer();

4.53 selection

获取编辑器当前的选区。如果未选中,则返回 null 。

editor.selection; // selection 或 null

selection 数据结构如下:

{"anchor": { "path": [1, 0], "offset": 8 },"focus": { "path": [1, 0], "offset": 10 }
}

4.54 select

选中一个指定的选区。

const newSelection = {anchor: { path: [1, 0], offset: 8 },focus: { path: [1, 0], offset: 10 },
};
editor.select(newSelection);

4.55 selectAll

选中所有内容

editor.selectAll();

4.56 deselect

取消选中

editor.deselect();

4.57 move

移动光标

editor.move(3); // 移动 3 个字符

4.58 moveReverse

反向移动光标

editor.moveReverse(2); // 反向移动 2 个字符

4.59 restoreSelection

恢复最近一次非 null 选区。如编辑器 blur 之后,再重新恢复选区。

editor.restoreSelection();

4.60 isSelectedAll

判断编辑器是否全部选中。

editor.isSelectedAll(); // true/false

4.61 getSelectionPosition

获取选区的定位,将视情况返回 left right top bottom 的其中几个。

editor.getSelectionPosition(); // 例如 { left: "80.15px", top: "116px" }

4.62 getNodePosition

获取某个节点的定位,将视情况返回 left right top bottom 的其中几个。

editor.getNodePosition(node); // 例如 { left: "80.15px", top: "116px" }

4.63 on

监听某个事件

editor.on("event-key", fn);

4.64 off

取消监听

editor.off("event-key", fn);

4.65 once

只监听一次

editor.once("event-key", fn);

4.66 emit

触发事件

editor.emit("event-key");

4.67 内置的事件

editor.on("fullScreen", () => {console.log("fullScreen");
});
editor.on("unFullScreen", () => {console.log("unFullScreen");
});
editor.on("scroll", () => {console.log("scroll");
});
editor.on("modalOrPanelShow", (modalOrPanel) => {console.log(modalOrPanel);
});
editor.on("modalOrPanelHide", () => {console.log("modalOrPanelHide");
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3015031.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

一键静音,iPhone勿扰模式助你远离干扰

在现代社会的快节奏生活中&#xff0c;我们时常被各种各样的通知、铃声和提示音所打扰&#xff0c;无法专注地工作或享受宁静的时光。而iPhone的勿扰模式功能&#xff0c;就像是一位贴心的助手&#xff0c;能够一键帮你屏蔽这些干扰&#xff0c;让你在需要的时候拥有一个清静的…

sqlserver中替换空格和换行

sqlserver 中换行符&#xff0c;如下&#xff1a; sql语句如下&#xff1a; //替换换行-使用char(10) select REPLACE(F_CNKITitle ,char(10),) title from tzkj_CNKIContent tc where --F_CnkiContentID ffdc7412-41e1-4d42-8693-cc79d0cf2dd3and len(REPLACE(F_CNKITitle ,…

使用Three.js开发一个3D案例Demo

使用Three.js开发一个3D案例 最近在找工作&#xff0c;发现好多招聘要求都需要会Three.js&#xff0c;以前接触比较多的是2D开发&#xff0c;也就是平面开发&#xff0c;用到的做多的技术就是d3.js&#xff0c;现在3D开发已经成为了大势所趋&#xff0c;所以就学习下Three.js。…

第二届生成式AI应用创新大赛

&#x1f525; 第二届生成式AI应用创新大赛 &#x1f331; 初赛正如火如荼地进行中&#xff0c;报名截止时间是5月15日&#xff01; ⏰ ⭐ 最激动人心的总决赛将于5月30日在亚马逊上海峰会上举行&#xff0c;届时会有权威评委现场点评&#xff01; &#x1f3a4; &#x1f3…

【微积分】微分方程的求解(必看)

文章目录 微分方程1.一阶微分方程1.1 可分离变量型微分方程1.2 一阶齐次微分方程1.3 一阶线性微分方程 2. 高阶微分方程2.1 可降阶的高阶微分方程求解&#xff08;以二阶为例&#xff09;2.2 二阶常系数线性微分方程2.2.1 二阶常系数齐次微分方程2.2.2 二阶常系数非齐次微分方程…

tkinter/python:第一个GUI程序——制作一个数据录入界面

下图是在网上搜寻的一个案例图样&#xff0c;经过了调整修改&#xff0c;登录时界面图如下&#xff1a; 登录后点击百货店铺按钮&#xff0c;界面如下 一、创建root窗口&#xff1a; geometry接收一个字符串&#xff0c;也就是需要建立的窗口尺寸和位置&#xff0c;geometry(…

字符设备驱动流程

字符设备驱动&#xff1a; linux系统驱动程序分为三大类&#xff0c;字符设备驱动&#xff0c;块设备驱动和网络设备驱动。其中字符设备驱动是使用最多的一种&#xff0c;从点灯到llC&#xff0c;SPI&#xff0c;音频设备等的驱动都是字符设备驱动。块设备和网络设备驱动要比字…

使用fitten code插件(vscode),替换通义千问,识别需求中的输入输出

今天我们介绍一个工具,具体介绍可以参考我的这篇文章的介绍,支持vs code 插件,Fitten Code是一款由非十科技开发的AI代码助手,旨在通过大模型驱动来提升编程效率和体验-免费神器-CSDN博客https://blog.csdn.net/lijigang100/article/details/137833223?spm=1001.2014.3001…

超越传统游戏:生成式人工智能对游戏的变革性影响

人工智能&#xff08;AI&#xff09;在游戏中的应用 游戏产业是一个充满活力、不断发展的领域&#xff0c;人工智能&#xff08;AI&#xff09;的融入对其产生了重大影响。这一技术进步彻底改变了游戏的开发、玩法和体验方式。本文分析的重点是传统人工智能和生成式人工智能在游…

【Java笔记】多线程:中断

线程中断的作用 线程中断可以使一个线程从等待状态变成就绪状态 使用线程中断&#xff0c;并不是要把线程给终止或是杀死&#xff0c;而是让线程不再继续等待&#xff0c;而是让线程不再继续等待&#xff0c;线程可以继续往下执行代码&#xff0c;线程发生中断后&#xff0c;会…

Linux网络编程(二) socket编程及其仿真

本节内容介绍Linux下进行网络编程所必须得socket接口的一些知识 一、socket地址函数 1.1、主机字节序和网络字节序 现代PC大多采用小端字节序&#xff0c;因此小端字节序又被称为主机字节序。 为了避免由于字节序导致的错误&#xff0c;发送端总是将字节序转换为大端字节序…

暖心又实用!母亲节教会妈妈这4招才是最贴心的礼物

母亲节就要到了&#xff0c;这个特殊的日子&#xff0c;我们总是想要为妈妈送上最真挚的祝福和关怀。在这个数字化时代&#xff0c;一部智能手机就能成为我们表达爱意的桥梁。今天&#xff0c;就让我们一起来看看华为手机的四个功能&#xff0c;让妈妈的手机使用体验更加便捷、…

C语言中的关键字static和extern

Hello,亲爱的小伙伴们&#xff0c;我又来了&#xff0c;上一期作者菌讲解了C语言中函数的知识点&#xff0c;得到了很好的反馈&#xff0c;这里作者菌感谢每一个至此我的小伙伴&#xff01;&#xff01;今天作者菌又来补充一些很有用的知识&#xff0c;感兴趣的uu们不要吝啬手中…

Jmeter 命令行压测 生成 HTML 测试报告,你真的会?

通常 Jmeter 的 GUI 模式仅用于调试&#xff0c;在实际的压测项目中&#xff0c;为了让压测机有更好的性能&#xff0c;多用 Jmeter 命令行来进行压测。 同时&#xff0c;JMeter 也支持生成 HTML 测试报告&#xff0c; 以便从测试计划中获得图表和统计信息。 以上定义的文件路…

Elementui的el-footer标签使用报错

Elementui的el-footer标签使用报错 其余标签的使用没有报错信息 el-footer的报错信息 原因: ​ 警告信息表示 Vue 不识别 <el-footer> 解决方式: 在组件中进行引入和暴露

Flume 的安装和使用方法

一、Flume的安装 1.下载压缩包 https://www.apache.org/dyn/closer.lua/flume/1.7.0/apache-flume-1.7.0-bin.tar.gz 2.上传到linux中 3.解压安装包 cd #进入加载压缩包目录sudo tar -zxvf apache-flume-1.7.0-bin.tar.gz -C /usr/local # 将 apache-flume-1.7.0-bin.tar.g…

119. 再谈接口幂等性

文章目录 0. 前言1. insert前先select2. 加悲观锁3. 加乐观锁5. 加唯一索引【配合 &#xff08;1. insert前先select &#xff09;最常用 】6. 建防重表6. 根据状态机7. 加分布式锁8. 获取token 0. 前言 在 93. 通用防重幂等设计 一文中&#xff0c;已经介绍过幂等的使用。该文…

力扣:63. 不同路径 II

63. 不同路径 II 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么…

C# Web控件与数据感应之 BaseDataList 类

目录 关于数据感应 BaseDataList 类 范例运行环境 pageview 方法 设计 实现 调用示例 数据源 调用 小结 关于数据感应 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;Web控件与数据源之间的交互&#xff0c;本文将继续介绍以与数据库提取数据并捆绑控件…