富文本编辑器 发表于 2023-03-01 | 分类于 Components 富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。最终权衡了一下选择了WangEditor。 Vue2Demo index.vue 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201<template> <div class="components-container"> <div style="border: 1px solid #ccc;"> <!-- 工具栏 --> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :default-config="toolbarConfig" :mode="mode" /> <!-- 编辑器 --> <Editor v-model="html" :style="{ height: height }" style="overflow-y: hidden" :default-config="editorConfig" :mode="mode" @onCreated="onCreated" /> </div> </div></template><script>import Vue from 'vue'import wsCache from '@/cache'import { Editor, Toolbar } from '@wangeditor/editor-for-vue'import toolbarKeys from '@/views/components-demo/toolbarKeys'export default { name: 'WangEditor', components: { Editor, Toolbar }, props: { id: { type: String, default: function() { return 'wangEditor' + +new Date() + ((Math.random() * 1000).toFixed(0) + '') } }, value: { type: String, default: '这里是placeHolder!' }, height: { type: [Number, String], required: false, default: '360px' }, // 是否可编辑 isEdit: { type: Boolean, default: true }, // 隐藏菜单 excludeKeys: { type: Array, default: () => [] } }, data() { return { editor: null, // 实例 html: '', // 默认内容 toolbarConfig: { toolbarKeys: toolbarKeys, // 不填即为默认配置 excludeKeys: this.excludeKeys // 隐藏 }, editorConfig: { // 工具栏配置 maxLength: 300, placeholder: '这里是placeHolder!', autoFocus: true, readOnly: !this.isEdit, // 只读、不可编辑 MENU_CONF: { // 所有的菜单配置,都要在 MENU_CONF 属性下 'uploadImage': { maxFileSize: 0.2 * 1024 * 1024, // 200k onBeforeUpload(file) { return file // 可以 return // 1. return file 或者 new 一个 file ,接下来将上传 // 2. return false ,不上传这个 file }, // 用户自定义上传图片 customUpload(file, insertFn) { const isLs200 = file.size / 1024 / 1024 < 0.2 if (!isLs200) { Vue.prototype.$message.error('上传失败,图片大小不可超过200KB!') return false } const axios = require('axios') const data = new FormData() data.append('files', file) const config = { method: 'post', url: '/operationsLog/uploadImage', // 上传图片地址 headers: { 'Content-Type': 'multipart/form-data', 'access-token': wsCache.get('userInfo').data.token }, data: data } axios(config) .then(function(res) { const url = 'https://220.160.52.164:8217/file/' + res.data.data.image1 // 拼接成可浏览的图片地址 insertFn(url, res.data.data.image1, url) // 插入图片 }) .catch(function(error) { console.log(error) }) } }, 'uploadVideo': { customUpload(file, insertFn) { const axios = require('axios') const data = new FormData() data.append('file', file) // file 即选中的文件 const config = { method: 'post', url: '/api/operationsLog/uploadVideo', // 上传图片地址 headers: { 'Content-Type': 'multipart/form-data', 'access-token': wsCache.get('userInfo').data.token }, data: data } axios(config) .then(function(res) { const url = res.data.data.video // 拼接成可浏览的图片地址 insertFn(url, url) // 插入图片 }) .catch(function(error) { console.log(error) }) } } } }, mode: 'default' // or 'simple' } }, watch: { html(val) { this.$nextTick(() => { console.log(this.html,'html') const editor = this.editor editor.setHtml(this.html) }) }, deep: true }, mounted() { this.$nextTick(() => { this.$nextTick(() => { const editor = this.editor editor.setHtml(this.value) if (this.isEdit) { editor.enable() } else { editor.disable() } }) }) }, beforeDestroy() { const editor = this.editor if (editor == null) return editor.destroy() // 组件销毁时,及时销毁 editor ,重要!!! }, methods: { onCreated(editor) { this.editor = Object.seal(editor) // 【注意】一定要用 Object.seal() 否则会报错 }, onChange(editor) { // console.log("工具栏配置", editor.getAllMenuKeys()); // 获取附件资源 const imgUrls = editor.getElemsByType('image') const videoUrls = editor.getElemsByType('video') const filePathArr = [] const ipUrl = 'https://220.160.52.164:8217/file/' imgUrls.map(item => { const imgObj = {} imgObj.filePath = item.src.split(ipUrl)[1] imgObj.fileStatus = '0' if (this.isEdit) { imgObj.operationsLogId = this.operationsLogId } filePathArr.push(imgObj) }) videoUrls.map(item => { const videoObj = {} videoObj.filePath = item.src videoObj.fileStatus = '1' filePathArr.push(videoObj) }) const obj = {} // obj.content = editor.getText() // 纯文本 obj.value = editor.getHtml() // 富文本 if (filePathArr.length === 0) { // 图片路径 obj.richTextList = null } else { obj.richTextList = filePathArr } // obj.isEmpty = editor.isEmpty() obj.txt = editor.getText().replace(/[\r\n]/g, '').replace(/\ +/g, '') this.$emit('changeContent', obj) } }}</script><style scoped></style><style src="@wangeditor/editor/dist/css/style.css"></style> toolbarKeys.js 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364const 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', // H1 'header2', // H2 'header3', // H3 'header4', // H4 'header5', // H5 'todo', // 代办 'redo', // 重做 'undo', // 撤销 'fullScreen', // 全屏 'enter', // 回车 'bulletedList', // 无序列表 'numberedList', // 有序列表 'insertTable', // 插入表格 'deleteTable', // 删除表格 'insertTableRow', // 插入行 'deleteTableRow', // 删除行 'insertTableCol', // 插入列 'deleteTableCol', // 删除列 'tableHeader', // 表头 'tableFullWidth', // 宽度自适应 'insertVideo', // 插入视频 'uploadVideo', // 上传视频 'editVideoSize', 'uploadImage', // 上传图片 'codeSelectLang'// 选择语言]export default toolbarKeys