Vue3 使用 富文本编辑器 wangeditor/editor-for-vue 配置详解
先上官网地址 wangEditor 5 点这里
- wangeditor 主要API
配置功能栏
let toolbarConfig = {
toolbarKeys: [
"bold", // 字体加粗
"underline", // 字体下划线
"italic", // 字体斜体
"through", // 字体删除线
"code", // 字体代码
"sub", // 下标 "sup", // 上标
"clearStyle", // 清除字体样式
"color", // 字体颜色
"bgColor", // 背景颜色
"fontSize", // 字体大小
"fontFamily", // 字体
// "indent", // 增加缩进
// "delIndent", // 减少缩进
// "justifyLeft", // 左对齐
// "justifyRight", // 右对齐
// "justifyCenter", // 居中对齐
// "justifyJustify", // 两端对齐
'|', // 分割线
"lineHeight", // 行间距
"insertImage", // 插入图片
"deleteImage", // 删除图片
"editImage", // 编辑图片
"viewImageLink", // 查看图片链接
"imageWidth30", // 图片宽度30%
"imageWidth50", // 图片宽度50%
"imageWidth100", // 图片宽度100%
"divider", // 分隔线
"emotion", // 表情
"insertLink", // 插入链接
"editLink", // 编辑链接
"unLink", // 取消链接
"viewLink", // 查看链接
"codeBlock", // 代码块
"blockquote", // 引用块
'|',
"headerSelect", // 头部类型选择
"header1", // 头部1
"header2", // 头部2
"header3", // 头部3
"header4", // 头部4
"header5", // 头部5
"todo", // 待办事项
"redo", // 重做
"undo", // 撤销
"fullScreen", // 全屏
"enter", // 换行
"bulletedList", // 无序列表
"numberedList", // 有序列表
"insertTable", // 插入表格
"deleteTable", // 删除表格
"insertTableRow", // 插入表格行
"deleteTableRow", // 删除表格行
"insertTableCol", // 插入表格列
"deleteTableCol", // 删除表格列
"tableHeader", // 表格标题
"tableFullWidth", // 表格全宽
// "insertVideo", // 插入视频
// "uploadVideo", // 上传视频
"editVideoSize", // 编辑视频大小
"uploadImage", // 上传图片
"codeSelectLang", // 选择代码语言
// 设置为下拉选择 --------------------------------------- 一下代码为下拉样式
{
key: 'group-video',
title: '视频', // 下拉名称
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>', // 下拉图标
menuKeys: ['insertVideo', 'uploadVideo'], // 插入视屏 // 视屏上传
},
'|',
{
key: 'group-justify',
title: '对齐',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'], // 对齐的四种方式
},
{
key: 'group-indent',
title: '缩进',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>',
menuKeys: ['indent', 'delIndent'], // 缩进的两种方式
},
]
};
编辑器配置
//编辑器配置
let editorConfig = {
placeholder: '请输入内容...', // 配置编辑器 placeholder
readOnly: false, // 配置编辑器是否只读,默认为 false
autoFocus: true, // 配置编辑器默认是否 focus ,默认为 true
scroll: true, // 配置编辑器是否支持滚动,默认为 true
maxLength: 1000, // 最大输入length
hoverbarKeys:{
'link': {
// 重写 link 元素的 hoverbar
menuKeys: ['editLink', 'unLink', 'viewLink'],
},
'image': {
// 清空 image 元素的 hoverbar
menuKeys: [],
}
},
onMaxLength:(editor)=>{
// 当达到 maxlength 限制时,触发该回调函数
},
onCreated: (editor) => {
// 编辑器创建完毕时的回调函数。
},
onChange: (editor) => {
// 编辑器内容、选区变化时的回调函数。
},
onDestroyed: (editor) => {
// 编辑器销毁时的回调函数。
},
onFocus: (editor) => {
// 编辑器 focus 时的回调函数。
},
onBlur: (editor) => {
// 编辑器 blur 时的回调函数。
},
customPaste: (editor) => {
// 编辑器 blur 时的回调函数。
},
customAlert: (s,t) => {
// 自定义编辑器 alert
}
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
// 插入图片
insertImage: {
onInsertedImage(){
},
},
// 配置上传图片
uploadImage: {
customUpload: (file, insertFn)=>{
// 上传图片的方法
},
},
// 配置上传视频
uploadVideo: {
customUpload: (file, insertFn)=>{
// 上传视频的方法
},
},
},
};
以上为基本常用的一些配置
- 使用方法
插件安装
yarn add @wangeditor/editor
# 或者 npm install @wangeditor/editor --save
yarn add @wangeditor/editor-for-vue
# 或者 npm install @wangeditor/editor-for-vue --save
组件封装
// 组件封装
// WangEditor.vue
<template>
<div style="border: 1px solid #ccc" v-loading="loading" element-loading-text="文件上传中...">
<div style="color: red; padding-left: 18px">注:视频最佳宽度700-900</div>
<Toolbar style="border-bottom: 1px solid #ccc" class="count-yc-box-title" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
<Editor
style="min-height: 250px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
class="count-yc-box"
/>
</div>
</template>
<script>
//script标签中引入
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { defineExpose, onMounted, watch } from 'vue';
import request from '@/utils/request'; // 这个是请求封装 请更换为你的地址
export default {
components: { Editor, Toolbar },
props: {
editValue: {
type: String,
default: '',
},
},
setup(props, { emit }) {
emits: ['select'];
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef();
console.log(editorRef, 'editor.getAllMenuKeys()');
// 内容 HTML
const valueHtml = ref('');
const loading = ref(false);
watch(
() => props.editValue,
(val) => {
//当编辑器的内容发生变化时,把值传给父组件
valueHtml.value = props.editValue;
},
{
deep: true,
immediate: true,
}
);
//配置功能栏
let toolbarConfig = {
toolbarKeys: [
'headerSelect',
'header1',
'header2',
'header3',
{
key: 'group-video',
title: '视频',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>',
menuKeys: ['insertVideo', 'uploadVideo'],
},
'blockquote',
'|',
'bold',
'underline',
'italic',
'lineHeight',
{
key: 'group-more-style',
title: '更多',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>',
menuKeys: ['through', 'code', 'sup', 'sub'],
},
'color',
'bgColor',
'|',
'fontSize',
{
key: 'group-justify',
title: '对齐',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'],
},
'todo',
'fontFamily',
{
key: 'group-indent',
title: '缩进',
iconSvg:
'<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>',
menuKeys: ['indent', 'delIndent'],
},
'|',
'emotion',
'insertLink',
'uploadImage',
'insertTable',
'codeBlock',
'divider',
'clearStyle',
'|',
'undo',
'redo',
],
};
const uploadImageList = ref([]);
const saveImageList = ref([]);
//上传本地图片
function update(file, insertFn) {
let formData = new FormData();
formData.append('file', file);
loading.value = true;
request({
url: '/common/file/upload',
headers: {
'Content-Type': 'multipart/form-data',
},
method: 'post',
timeout: 50000,
data: formData,
})
.then((res) => {
if (res.code === 200) {
const src = res.data.fileUrl;
insertFn(src, '百度 logo', src);
loading.value = false;
} else {
loading.value = false;
}
})
.catch(() => {
loading.value = false;
});
}
function getOnInsertedImage(imageNode) {
uploadImageList.value.push(imageNode);
}
//编辑器配置
let editorConfig = {
placeholder: '请输入内容...',
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
insertImage: {
onInsertedImage: getOnInsertedImage(),
},
// 配置上传图片
uploadImage: {
customUpload: update,
},
uploadVideo: {
customUpload: update,
},
},
};
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
function copyObject(obj) {
return JSON.parse(JSON.stringify(obj));
}
const handleCreated = (editor) => {
editorRef.value = editor; // 记录 editor 实例,重要!
saveImageList.value = editor.getElemsByType('image');
uploadImageList.value = copyObject(saveImageList.value);
};
watch(
() => valueHtml.value,
() => {
//当编辑器的内容发生变化时,把值传给父组件
emit('select', valueHtml.value);
}
);
// 一下方法 用作回调 但暂时未调用
const handleChange = (editor) => {
console.log('change:', editor.children);
};
const handleDestroyed = (editor) => {
console.log('destroyed', editor);
};
const handleFocus = (editor) => {
console.log('focus', editor);
};
const handleBlur = (editor) => {
console.log('blur', editor);
};
const customAlert = (info, type) => {
console.log(`【自定义提示】${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)
};
//父组件调用子组件的方法清空编辑器内容
const abc = function () {
valueHtml.value = '';
};
//暴露该方法,defineExpose要引入
defineExpose({
abc,
valueHtml,
});
return {
editorRef,
valueHtml,
mode: 'default', // 或 'simple'
toolbarConfig,
editorConfig,
handleCreated,
handleChange,
handleDestroyed,
handleFocus,
handleBlur,
customAlert,
customPaste,
abc,
loading,
};
},
};
</script>
组件使用
<template>
<el-form ref="ruleFormRef" :model="ruleForm" class="demo-ruleForm" label-width="80px">
<el-form-item label="内容" prop="content" v-if="ruleForm.radio1 == 1" class="label-befor">
<WangEditor class="WangEditor" @select="getRich" ref="childrenRef" :editValue="editValue" />
</el-form-item>
</el-form>
</template>
<script setup>
import { onMounted, reactive, ref, watch, nextTick } from 'vue'
import WangEditor from '@/custom/WangEditor.vue'
const props = defineProps({
// 父页面传递的数据
dataRow: {
type: Object,
default: () => {
return { "title": "", "languageType": 1, "contentType": 1, "content": "", "remark": null }
}
},
})
const ruleFormRef = ref()
const ruleForm = reactive({
content: "",
})
const editValue = ref("")
watch(props, (newUser, oldUser) => {
if (props.dataRow && props.dataRow.id) {
// 富文本回显
ruleForm.content = props.dataRow.content
editValue.value = ruleForm.content
}
}, {
deep: true,
immediate: true
});
//当编辑器的内容更新时,获取该值
const getRich = function (value) {
ruleForm.content = value
}
defineExpose({
ruleForm,
})
</script>
上图
以上的代码封装 以及使用方法可直接复制使用 但需要修改你自己的上传接口。
以上就是wangeditor/editor-for-vue 基本配置详解,希望可以帮到您!