基于WangEditor5的Mention功能实现插入自定义标签功能
背景
项目需求中有涉及编辑器提及@功能,考虑项目中已使用WangEditor富文本编辑器并且V5版本实现了@Mention插件功能,于是便升级富文本版本加入@Mention功能。趁周末之余,在@Mention功能上改写测试性的自定义Tag插入功能。
实现
首先将自定义标签插入封装为一个插件,然后在Editor中注册使用,插件代码仓库 github地址。(本地项目使用:Vue3+Typescript,插件的封装可参考Wang Editor官网)
import { Boot } from '@wangeditor/editor'
import tagModule from '../plugins/tag/index'
// 注册插件
Boot.registerModule(tagModule)
加入本地测试数据
// 代码参照: Wang Editor[Mention插件](https://github.com/wangfupeng1988/vue2-wangeditor-demo/blob/master/src/components/MyEditorWithMention.vue)
// template
<ul style="display:flex; list-style:none;margin-bottom: 10px;">
<li class="my-button" v-for="item in mockTags" :key="item.id" @click="insertTag(item)">{{ item.label}}</li>
</ul>
// js
const mockTags = [
{id: 1, label: '自定义标签1'},
{id: 2, label: '自定义标签2'},
{id: 3, label: '自定义标签3'},
{id: 4, label: '自定义标签4'}
]
// 插入insertTag(=
const insertTag = ({id, label}) => {
const tagNode = {
type: "tag", // 唯一
value: label,
info: { id, label },
style: { // 自定义tag样式
fontSize: '14px',
// color: "#f00",
},
children: [{ text: "" }], // 必须有一个空 text 作为 children
// tooltip 分支功能
tooltip: label + '自定义标签', // tooltip(非必选, 默认为label)
tooltipStyle: { // tooltip 自定义样式(非必选)
background: 'white',
color: '#000',
border: '1px solid #303333',
}
};
const editor = editorRef.value;
if (editor) {
editor.restoreSelection();
editor.insertNode(tagNode);
editor.move(1);
}
}
最终代码
<template>
<div class="editor-wrapper">
<div class="editor-operate">
<ul style="display:flex; list-style:none;margin-bottom: 10px;">
<li class="my-button" v-for="item in mockTags" :key="item.id" @click="insertTag(item)">{{ item.label}}</li>
</ul>
</div>
<div style="border: 1px solid #ccc; margin-top: 10px">
<Toolbar
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="editorMode"
v-if="showToolBar"
style="border-bottom: 1px solid #ccc"
/>
<Editor
:defaultConfig="editorConfig"
:mode="editorMode"
v-model="valueHtml"
style="height: 400px; overflow-y: hidden"
@onCreated="handleCreated"
@onChange="handleChange"
@onDestroyed="handleDestroyed"
/>
</div>
<div style="margin-top: 10px">
<textarea
v-model="valueHtml"
readonly
style="width: 100%; height: 200px; outline: none"
></textarea>
</div>
</div>
</template>
<script lang="ts" setup>
import "@wangeditor/editor/dist/css/style.css";
import { onBeforeUnmount, ref, shallowRef, onMounted, nextTick } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { Boot } from '@wangeditor/editor'
import tagModule from '../plugins/tag/index'
// 注册插件
Boot.registerModule(tagModule)
const props = defineProps({
showToolBar: {
type: Boolean,
default: false,
},
});
const editorMode = "simple";
// 编辑器实例,必须用 shallowRef,重要!
const editorRef = shallowRef();
const valueHtml = ref("");
const toolbarConfig = {};
const editorConfig = { placeholder: "请输入内容..." };
// 销毁组件
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
// 编辑器回调函数
const handleCreated = (editor) => {
console.log("created", editor);
editorRef.value = editor;
};
const mockTags = [
{id: 1, label: '自定义标签1'},
{id: 2, label: '自定义标签2'},
{id: 3, label: '自定义标签3'},
{id: 4, label: '自定义标签4'}
]
const insertTag = ({id, label}) => {
const tagNode = {
type: "tag", // 唯一
value: label,
info: { id, label },
style: {
fontSize: '14px',
// color: "#f00",
},
children: [{ text: "" }], // 必须有一个空 text 作为 children
};
const editor = editorRef.value;
if (editor) {
editor.restoreSelection();
editor.insertNode(tagNode);
editor.move(1);
}
}
const handleChange = async (editor) => {
console.log(editor.isFocused(),'---')
};
</script>
<style>
/* :root{
--w-e-textarea-tag-bg-color: #ecf5ff;
--w-e-textarea-tag-color: #409eff;
--w-e-textarea-tag-border-color: #d9ecff
} */
.editor-wrapper .w-e-text-container {
text-align: left;
}
.my-button {
border: 1px solid #ccc;
padding: 8px 12px;
margin-right: 12px;
color: #333;
border-radius: 3px;
cursor: pointer;
}
.editor-operate {
text-align: left;
}
</style>
实现效果

更新
- 项目结构调整
- 更新WangEditor至wangEditor-next版本
{
"dependencies": {
"@wangeditor-next/editor": "^5.1.1",
"@wangeditor-next/editor-for-vue": "^5.1.12",
...
},
}
- 补充tooltip显示