vue3集成tinymce富文本编辑器
前言:因为公司要换富文本编辑器,思前想后选择了tinymce,记录一下我的使用方法以及使用时遇到的坑
效果图
正文:
1.安装依赖
npm i @tinymce/tinymce-vue tinymce
这里我选择的是5.0.0的tinymce-vue,5.10.7的tinymce,不建议使用tinymce6的版本
“@tinymce/tinymce-vue”: “^5.0.0”,
“tinymce”: “^5.10.7”,
2.建tinymce文件夹
在public下建tinymce文件夹,用来存放语言包和皮肤包,官网下载需要的语言包:https://www.tiny.cloud/get-tiny/language-packages/
在node_modules/tinymce/skins,把整个skins文件夹复制过来
3.封装组件TEditor(自己取名)
- 引入依赖
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver'
import 'tinymce/icons/default'
- 配置tinymce初始值
init: {
height: this.height,
emoticons_database_url: process.env.BASE_URL + '/tinymce/langs/emojis.js',
language_url: process.env.BASE_URL + '/tinymce/langs/zh-Hans.js',
language: 'zh-Hans',
// 皮肤:这里引入的是public下的资源文件
skin_url: process.env.BASE_URL + '/tinymce/skins/ui/oxide',
plugins: this.plugins,
toolbar: this.toolbar,
content_css: process.env.BASE_URL + '/tinymce/skins/content/default/content.css',
branding: false,
// 隐藏菜单栏
menubar: false,
// 是否显示底部状态栏
statusbar: false,
// convert_urls: false,
// 初始化完成
init_instance_callback: (editor) => {
console.log('初始化完成:', editor)
},
images_upload_handler: (blobInfo, success, failure) => {
if(blobInfo.blob().size / 1024 / 1024 > 10){
failure('上传失败,图片大小请控制在 10M 以内')
}else{
const params = new FormData()
params.append('file', blobInfo.blob())
axios({
url: `${this.app.proxy.$apiConfig.flowbaas}/WF/Ath/AttachmentUploadRichText.do`,
method: 'post',
data: params,
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
if(res.data.errno === 0){
success(res.data.data.url) //上传成功,在成功函数里填入图片路径
}else{
failure('上传失败')
}
}).catch(() => {
failure('上传出错,服务器开小差了呢')
})
}
}
},
要注意语言包的路径和皮肤包的路径,我这项目需要加上process.env.BASE_URL,正常情况下可以不加,上传图片的方法images_upload_handler也要根据实际情况修改
- 完整组件如下
<template>
<div class='tinymce-box'>
<editor v-model='textContent' :init='init' :disabled='disabled' @onClick='onClick'></editor>
</div>
</template>
<script>
import { getCurrentInstance } from 'vue'
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver' // 主题文件
import 'tinymce/icons/default'
// import 'tinymce/models/dom'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/emoticons'
import 'tinymce/plugins/link'
import 'tinymce/plugins/image'
import 'tinymce/plugins/table'
import 'tinymce/plugins/code'
import 'tinymce/plugins/hr'
import 'tinymce/plugins/fullscreen'
import axios from 'axios'
export default {
name: 'Tinymce',
components: { Editor },
props: {
height: {
type: String,
default: '300'
},
value: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default: 'lists emoticons link image table code hr fullscreen'
},
toolbar: {
type: [String, Array],
// eslint-disable-next-line vue/require-valid-default-prop
default: ['blockquote | bold underline italic strikethrough superscript subscript removeformat | fontsizeselect fontselect styleselect',
'bullist numlist align | emoticons link image table code hr | undo redo | fullscreen']
}
},
data() {
return {
app: getCurrentInstance(),
init: {
height: this.height,
emoticons_database_url: process.env.BASE_URL + '/tinymce/langs/emojis.js',
language_url: process.env.BASE_URL + '/tinymce/langs/zh-Hans.js',
language: 'zh-Hans',
// 皮肤:这里引入的是public下的资源文件
skin_url: process.env.BASE_URL + '/tinymce/skins/ui/oxide',
// skin_url: 'tinymce/skins/ui/oxide-dark',//黑色系
plugins: this.plugins,
toolbar: this.toolbar,
content_css: process.env.BASE_URL + '/tinymce/skins/content/default/content.css',
branding: false,
// 隐藏菜单栏
menubar: false,
// 是否显示底部状态栏
statusbar: false,
// convert_urls: false,
// 初始化完成
init_instance_callback: (editor) => {
console.log('初始化完成:', editor)
},
images_upload_handler: (blobInfo, success, failure) => {
if(blobInfo.blob().size / 1024 / 1024 > 10){
failure('上传失败,图片大小请控制在 10M 以内')
}else{
const params = new FormData()
params.append('file', blobInfo.blob())
axios({
url: `${this.app.proxy.$apiConfig.flowbaas}/WF/Ath/AttachmentUploadRichText.do`,
method: 'post',
data: params,
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
if(res.data.errno === 0){
success(res.data.data.url) //上传成功,在成功函数里填入图片路径
}else{
failure('上传失败')
}
}).catch(() => {
failure('上传出错,服务器开小差了呢')
})
}
}
},
textContent: this.value
}
},
watch: {
value (newValue) {
console.log(newValue, '1')
this.textContent = newValue
},
textContent (newValue) {
// 自定义事件给父组件传递数据
console.log(newValue, '2')
this.$emit('input', newValue)
}
},
// 实例创建完成
created() {
},
// 组件挂载完毕
mounted() {
// 初始化 tinymce
tinymce.init({})
},
methods: {
onClick (e) {
// 自定义事件给父组件传递数据
this.$emit('onClick', e, tinymce)
},
// 可以添加一些自己的自定义事件,如清空内容
clear () {
this.textContent = ''
}
}
}
</script>
<style scoped>
.tinymce-box{
margin: 10px
}
</style>
有几个要注意的地方,1、表情功能可能会找不到路径,然后报错,可以把依赖包里的emojis.js复制过来引入emoticons_database_url,
2、toolbar和plugins的配置,这两个按需配置,可以参考这篇文章 toolbar配置
3、图片上传根据实际情况修改接口
4、调用组件
<tinymce :height="300" ref="editor" :value="Value"></tinymce>
import Tinymce from './TEditor.vue'
components: { Tinymce }
我这个是vue3版本的,vue2版本的可能有出入,也大差不差吧