安装
npm i tinymce@5.10.9 -S
npm i @tinymce/tinymce-vue@3.0.1 -S
在public文件下创建tinymce文件夹(需要包含langs和skins)
【注意】:vue2使用tinymce富文本编辑器在node_modules直接引用中文包合skins下的样式好像不起作用,放在public下去引入就没问题
- 在node_modules中tinymce依赖包,找到其下面的skins文件下,直接复制,粘贴到src/assets/tinymce目录下;
- 先到官网下载中文翻译文件备用,将下载的zh_CN.js文件放在langs文件夹下;
官网
封装组件tinymce.vue
<template>
<div>
<editor
v-model="myValue"
:init="init"
:disabled="disabled"
@onClick="onClick"
>
</editor>
</div>
</template>
<script>
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/skins/ui/oxide/skin.css";
import "tinymce/themes/silver/theme";
import 'tinymce/icons/default/icons'
import "tinymce/icons/default"; // 图标 -解决测试环境找不icon问题
//下面这些引入路径中带plugins的都是引入安装的依赖包里面的插件;
//如果你想使用和展示该插件功能,就要先引入
import 'tinymce/plugins/autolink'
import "tinymce/plugins/image";
import 'tinymce/plugins/media'
import 'tinymce/plugins/autoresize'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/table'
import "tinymce/plugins/lists";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/hr";
import "tinymce/plugins/preview";
import "tinymce/plugins/print";
import apiCommon from '@/api/common'
export default {
name: "tinymce",
components: {
Editor,
},
props: {
//传入一个value,使组件支持v-model绑定
value: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
// 配置要使用的插件:
plugins: {
type: [String, Array],
default:
"autolink autoresize fullscreen image insertdatetime link lists media preview table wordcount code searchreplace",
},
// 配置工具栏:
toolbar: {
type: [String, Array],
default:
"undo redo | " +
"blocks | " +
"formatselect fontselect fontsizeselect | " +
"lineheight | " +
"bold italic underline strikethrough | "+
"alignleft aligncenter alignright alignjustify | "+
"forecolor backcolor removeformat | "+
"bullist numlist outdent indent | "+
"link image media table insertdatetime searchreplace | "+
"preview fullscreen print | ",
},
},
data() {
return {
//初始化配置
init: {
selector: 'textarea',
// 配置中文:
language_url: '/tinymce/langs/zh_CN.js', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
language: 'zh_CN',
// skin_url: '/tinymce/skins/ui/oxide', // 这样有问题
// content_css: 'tinymce/skins/content/default/content.min.css', // 这样有问题
skin_url: '/tinymce/skins/ui/oxide', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
content_css: '/tinymce/skins/content/default/content.min.css', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
min_height: 250,
max_height: 600,
plugins: this.plugins,
toolbar: this.toolbar,
branding: false,
menubar: false,
toolbar_mode: 'sliding',
insertdatetime_formats: [
'%Y年%m月%d日',
'%H点%M分%S秒',
'%Y-%m-%d',
'%H:%M:%S',
],
// 默认单位是pt,现改为px
font_size_formats: '9px 10px 11px 12px 14px 16px 18px 20px 22px 24px 26px 28px 36px 42px 48px 72px',
// 配置工具栏时添加的 fontsizeinput 工具可以展示一个可输入字号的组件,默认单位是pt,现改为px
font_size_input_default_unit: 'px',
// 官网地址:https://www.tiny.cloud/docs/tinymce/6/file-image-upload/#images_upload_handler
// 自定义图像和文件的处理方式
images_upload_handler: (blobInfo, success, failure) => {
let formData = new FormData()
formData.append('multipartFiles', blobInfo.blob(), blobInfo.filename())
apiCommon.uploadFileApi(formData).then(res=>{//使用axios进行图片上传,注意this是否引入成功
const [url] = res.data
success(url)
}).catch(()=>{
failure("上传出错,服务器开小差了呢")
})
},
//自定义文件选择器的回调内容
file_picker_callback(callback, value, meta) {
if (meta.filetype === 'media') {
// 模拟上传本地视频
const input = document.createElement('input')
input.setAttribute('type', 'file')
input.setAttribute('accept', '.mp4')
input.onchange = function (e) {
const file = e.target.files[0]
const formData = new FormData()
formData.append('multipartFiles', file, file.name)
// 请求文件上传接口
apiCommon.uploadFileApi(formData).then((res) => {
const [url] = res.data
callback(url)
})
}
input.click()
}
if (meta.filetype === 'image') {
// 模拟上传本地图片
const input = document.createElement('input')
input.setAttribute('type', 'file')
input.setAttribute('accept', '.png,.jpg,.jpeg,.jpeg,.gif,.bmp,.webp')
input.onchange = function (e) {
const file = e.target.files[0]
const formData = new FormData()
formData.append('multipartFiles', file, file.name)
// 请求文件上传接口
apiCommon.uploadFileApi(formData).then((res) => {
const [url] = res.data
callback(url)
})
}
input.click()
}
},
// //设置默认展示的字体和字号
// setup: function(editor) {
// editor.on('init', function(ed) {
// this.getBody().style.fontSize = '16px';
// this.getBody().style.fontFamily = '微软雅黑';
// });
// },
resize: true,
},
myValue: this.value,
};
},
mounted() {
tinymce.init({});
},
methods: {
onClick(e) {
this.$emit("onClick", e, tinymce);
},
clear() {
this.myValue = "";
},
},
watch: {
value(newValue) {
this.myValue = newValue;
},
myValue(newValue) {
this.$emit("input", newValue);
},
},
};
</script>
<style lang="less" scoped>
.preview {
margin-top: 10px;
&::before {
display: block;
content: "预览:";
}
}
</style>
<style lang="less">
// 提高TinyMCE下拉菜单的层级
.tox-tinymce-aux {
z-index: 10000 !important;
}
// 全屏层级
// .tox-fullscreen {
// z-index: 2001 !important;
// }
.tox-tbtn--bespoke {
background: #f7f7f7 !important;
height: 28px !important;
line-height: 28px !important;
margin-right: 10px !important;
&:last-child {
margin-right: 0 !important;
}
}
</style>
组件中使用封装组件tinymce.vue
<Tinymce v-model="newsForm.content" />
遇到的问题
1、层级问题
如果在element-ui等组件库的弹窗使用TinyMCE编辑器时,可能TinyMCE提示框或下拉菜单等的层级比弹窗组件层级低而不会显示。因此需要提高TinyMCE下拉菜单的层级:
<style lang="less">
.tox-tinymce-aux {
z-index: 10000 !important;
}
</style>
2、tinymce中使用media,视频保存到编辑区域时,会出现两个video,点击空白会消失一个,再点击video又出现两个,并且没有官方那个可以自己缩放的效果
【原因】:skins下的东西没有正确引入,就入上面所说直接引入skins下的会报错,要把skins放在public下去引入