前言
若依RuoYi-Vue
自带的富文本编辑器是quill
,但是quill
的功能比较少,没有TinyMCE
插件多。
安装tinymce、tinymce-vue
注意:基于vue2
npm install tinymce@5.4.1 -S --registry=https://registry.npmmirror.com
npm install @tinymce/tinymce-vue@3.0.1 -S --registry=https://registry.npmmirror.com
配置中文语言包
下载地址:https://www.tiny.cloud/get-tiny/language-packages/
下载完后放到静态文件public
目录下,在public
目录下新建tinymce
目录,将上面下载的语言包中的zh_CN.js
放到该目录
配置
在node_modules里面找到tinymce目录,将此目录下skins目录复制到public/tinymce里面
解决页面被覆盖问题
层级错误,和element
框架的el-dialog
冲突,需要调整z-index
修改:
ruoyi-ui/src/assets/styles/index.scss
文件,添加如下css
.tox-fullscreen .tox.tox-tinymce.tox-fullscreen {
z-index: 8000 !important;
}
.tox-tinymce-aux {
z-index: 8001 !important;
}
配置行高插件
下载行高插件:http://tinymce.ax-z.cn/more-plugins/lineheight.php
放在
ruoyi-ui/src/tinymcePlugins
文件夹下
并在init
中配置plugins
和toolbar
import '@/tinymcePlugins/lineheight/plugin';
tinymce.init({
plugins: "lineheight",
toolbar: "lineheight",
});
配置段落间距插件
npm install tinymce-paragraphspacing
并在init
中配置plugins
和toolbar
import 'tinymce-paragraphspacing'
tinymce.init({
plugins: "paragraphspacing",
toolbar: "paragraphspacing",
});
配置首行缩进插件
下载插件:http://tinymce.ax-z.cn/more-plugins/indent2em.php
放在ruoyi-ui/src/tinymcePlugins
文件夹下,并在init
中配置plugins
和toolbar
import '@/tinymcePlugins/indent2em/plugin';
tinymce.init({
plugins: "indent2em",
toolbar: "indent2em",
});
配置文字间距插件
下载插件:https://github.com/Five-great/tinymce-plugins
把里面的letterspacing
文件夹放在ruoyi-ui/src/tinymcePlugins
文件夹下,并在init
中配置plugins
和toolbar
import '@/tinymcePlugins/letterspacing';
tinymce.init({
plugins: "letterspacing",
toolbar: "letterspacing",
});
封装为组件
创建文件:ruoyi-ui/src/components/TinyEditor/index.vue
<template>
<div class="tinymce-box">
<TinymceVueEdit
v-model="myValue"
:init="init"
:disabled="disabled"
@click="onClick"
>
</TinymceVueEdit>
</div>
</template>
<script>
// 文档 http://tinymce.ax-z.cn/
// 引入组件
import tinymce from 'tinymce/tinymce'; // tinymce默认hidden,不引入不显示
import Editor from '@tinymce/tinymce-vue';
import request from '@/utils/request';
// // 引入富文本编辑器主题的js和css
// import 'tinymce/skins/content/default/content.css';
import 'tinymce/themes/silver/theme.min.js';
import 'tinymce/icons/default/icons' // 解决了icons.js 报错Unexpected token '<'
// 编辑器插件plugins
// 更多插件参考:https://www.tiny.cloud/docs/plugins/
import 'tinymce/plugins/image'; // 插入上传图片插件
import 'tinymce/plugins/media'; // 插入视频插件
import 'tinymce/plugins/table'; // 插入表格插件
import 'tinymce/plugins/lists'; // 列表插件
import 'tinymce/plugins/wordcount'; // 字数统计插件
import 'tinymce/plugins/link';
import 'tinymce/plugins/code';
import 'tinymce/plugins/preview';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/help';
import '@/tinymcePlugins/lineheight/plugin';
import '@/tinymcePlugins/indent2em/plugin';
import '@/tinymcePlugins/letterspacing';
import 'tinymce-paragraphspacing'
import {getToken} from '@/utils/auth';
export default {
components: {
TinymceVueEdit: Editor
},
name: 'TinyEditor',
props: {
// 默认的富文本内容
value: {
type: String,
default: ''
},
// 禁用
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default: 'letterspacing indent2em paragraphspacing link lineheight lists image code table wordcount media preview fullscreen'
// 其他工具: 'help'
},
toolbar: {
type: [String, Array],
// default: 'bold italic underline strikethrough | fontsizeselect | formatselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent blockquote | undo redo | link unlink code lists table image media | removeformat | fullscreen preview'
default: 'undo redo | preview code fullscreen | styleselect lineheight paragraphspacing indent2em letterspacing | fontsizeselect bold italic underline strikethrough forecolor backcolor | link image media blockquote removeformat codesample alignleft aligncenter alignright alignjustify| indent outdent bullist numlist table subscript superscript'
}
},
data() {
let _this = this;
return {
uploadUrl: "/common/upload", // 上传的图片服务器地址
refresh: true,
init: {
toolbar_mode: 'wrap',
language_url: `/tinymce/zh_CN.js`,
language: 'zh_CN',
skin_url: `/tinymce/skins/ui/oxide`,
// skin_url: 'tinymce/skins/ui/oxide-dark', // 暗色系
content_css: `/tinymce/skins/content/default/content.css`,
convert_urls: false,
height: 450,
// content_css(为编辑区指定css文件),加上就不显示字数统计了
// content_css: `${this.baseUrl}tinymce/skins/content/default/content.css`,
// (指定需加载的插件)
plugins: this.plugins,
toolbar: this.toolbar, // (自定义工具栏)
// selector: '#tinydemo',
media_alt_source: false, // 禁用备用源
media_poster: false, // 禁用海报图
media_filter_html: false, // 关闭HTML过滤
statusbar: true, // 底部的状态栏
menubar: 'file edit insert view format table tools help', // (1级菜单)最上方的菜单
branding: false, // (隐藏右下角技术支持)水印“Powered by TinyMCE”
// 文件上传
file_picker_callback: function (callback, value, meta) {
console.log(meta.filetype)
let filetype;
// 上传视频
if (meta.filetype === "media") {
filetype='.mp4, .avi, .mpg, .mpeg, .wmv, .mov, .flv, .swf, .rm, .ram, .mkv'; //限制文件的上传类型
}
// 上传图片
else if (meta.filetype === "image") {
filetype='.jpg, .jpeg, .png, .svg, .webp, .tif, .tiff, .gif, .raw';
}
// 上传文件
else if (meta.filetype === "file") {
filetype='.pdf, .txt, .zip, .rar, .doc, .docx, .xls, .xlsx, .ppt, .pptx'; //限制文件的上传类型
}
// 上传文件
// 创建一个input,模拟打开选择文件
let input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', filetype);
input.onchange = function () {
// 只选择一个
let file = this.files[0];
let fd = new FormData();
fd.append('file', file);
_this.saveImgOrFile(fd).then((response) => {
callback(process.env.VUE_APP_BASE_API + response.fileName, {width: '100%', height: 'auto'});
});
};
input.click();
}
},
myValue: ''
};
},
mounted() {
tinymce.init({});
},
methods: {
// 图片上传接口
saveImgOrFile(params) {
return request({
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + getToken()
},
url: this.uploadUrl,
method: 'post',
data: params
});
},
// 添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available events
// 需要什么事件可以自己增加
onClick(e) {
this.$emit('onClick', e, tinymce);
}
},
watch: {
value: {
deep: true,
immediate: true,
handler(newValue, oldValue) {
this.$set(this, 'myValue', newValue || '');
}
},
myValue(newValue = '') {
this.$emit('input', newValue || '');
}
}
};
</script>
使用
一定要加v-if="open"
,否则el-dialog
关闭后富文本不会关闭导致第二次打开无法渲染,需要跟随el-dialog
一起关闭
<el-form-item label="内容" prop="content">
<TinyEditor v-if="open" v-model="form.content"></TinyEditor>
</el-form-item>