背景
项目为 vue2.X ,后台管理系统,新需求需要富文本支持数学公式。
原来的后台管理系统是 vue-admin 改造来的,原来自带的富文本版本为3.x的版本,且为cdn直接引入的。
从零开始
网上找到了 tinymce
的插件 kityformula-editor
可以实现数学公式的输入,但是在原来的版本上无法进行操作,一直无法显示。
后来百度得知tinymce 3.x 版本不支持数学公式,4之后的版本才支持数学公式(暂未确定)。
再加上原来的 tinymce
是通过 cdn 的方式引入,没有进行本地化,添加外部插件不方便,所以决定从零开始。
下载对应版本的npm包
vue 和 tinymce
有一定的版本对应,版本不对的时候会有奇怪的报错。
vue2
对应的tinymce
版本的大版本号应该是5(我这里下载的是6,暂未发现问题)
tinymce-vue
对应的版本大版本号是3
yarn add tinymce@^6
yarn add @tinymce/tinymce-vue@^3
创建组件
创建vue文件,写富文本组件。不过不用引入两个包,引入tinymce-vue就可以了。
<template>
<div class="tinymce-container">
<editor v-model="myValue" class="editor" :init="init" :disabled="disabled" />
</div>
</template>
import Editor from '@tinymce/tinymce-vue';
// data数据
init: {
language: 'zh_CN', // 汉化
language_url: '/static/tinymce/langs/zh_CN.js', // 这里的地址指向 public 目录下的路径
}
页面中的使用
<Tinymce v-model="tinymceData" />
API key
此时页面会报错,内容如下:
A valid API key is required, starting 2024, to continue using TinyMCE. Please alert your admin sign-up to get your free API key
原因:我们只导入import Editor from '@tinymce/tinymce-vue'
,那么tinymce
会从云上调用组件,此刻若没api-key的话,会有错误提示
这里可以去官网获取一个免费的key,但是加上之后会有下一个错误,域名没有注册。
本地化
本地化包地址为:https://www.tiny.cloud/get-tiny/self-hosted/
上面问题的常用解决方式为本地化,下载本地的包之后,解压之后放在public的static文件夹下(原因是由于我们的后台项目只配置了/piblic/static/
文件夹的服务化,可以支持域名加 /static
直接访问,放在其他位置,测试环境和正式环境会出现notFound或者404)。
并不需要将解压的文件全部放到这个文件夹下面,需要用到的也就是skins,用于css的调用。
此时不需要import引入,只需在init里面配置skin_url和 content_url即可。
其他的langs为语言包,plugins里面只需要放额外的插件即可,原本的tinymce包含的插件不需要放在这里。
还有就是 tinymce 需要import引入:import 'tinymce/tinymce'
需要用到的各种插件也需要手动引入
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/tinymce'
// models
import 'tinymce/models/dom'
// Theme
import 'tinymce/themes/silver/theme'
// icons
import 'tinymce/icons/default/icons'
// Skins 这三个css的调用就不需要设置 skin_url 了
// import 'tinymce/skins/ui/oxide/skin.min.css'
// import 'tinymce/skins/ui/oxide/content.min.css'
// import 'tinymce/skins/content/default/content.min.css'
// Plugins 组件根据init中调用情况自行加载
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/quickbars'
// init 的内容
promotion: false, // 这个要加上,不然富文本会出现更新按钮的
// skin: 'oxide', // 默认值是 oxide 和skin_url配合使用
skin_url: '/static/tinymce/skins/ui/oxide', // 官方自带三种主题,gray,lightgray,flat
content_css: '/static/tinymce/skins/content/default/content.min.css', // 官方自带三种主题,gray,lightgray,flat
branding: false // 去掉编辑器右下角的广告
中文包
这时正常情况下就是可以使用了的,但是由于npm包里面是没有自带中文包的,所以此时是全英文的。
如果需要变成中文的,则需要去下载一个中文包,解压之后放在public的static文件夹下。
组件的init里面要添加 language_url
language: 'zh_CN', // 汉化
language_url: '/static/tinymce/langs/zh_CN.js', // 这里的地址指向 public 目录下的路径
添加数学公式插件 kityformula-editor
-
首先下载插件的压缩包,地址为:kityformula-editor
-
下载之后解压放在public对应的plugins文件夹下
-
这里的
plugins.js
和plugin.min.js
需要改里面的baseURL
-
init里的
plugins
和toolbar
分别加上kityformula-editor
-
再加上引入路径:
external_plugins: { // 外部插件
'kityformula-editor': '/static/tinymce/plugins/kityformula-editor/plugin.min.js'
},
- 查看效果
完整代码
<template>
<div class="tinymce-container">
<editor v-model="myValue" class="editor" :init="init" :disabled="disabled" />
</div>
</template>
<script>
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/tinymce'
// models
import 'tinymce/models/dom'
// Theme
import 'tinymce/themes/silver/theme'
// icons
import 'tinymce/icons/default/icons'
// Skins 这三个css的调用就不需要设置 skin_url 了
// import 'tinymce/skins/ui/oxide/skin.min.css'
// import 'tinymce/skins/ui/oxide/content.min.css'
// import 'tinymce/skins/content/default/content.min.css'
// Plugins 组件根据init中调用情况自行加载
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/quickbars'
// import 'tinymce/plugins/paste'
export default {
components: {
Editor
},
props: {
value: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default:
'link lists image code table wordcount kityformula-editor'
// 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr nonbreaking insertdatetime advlist lists wordcount imagetools textpattern autosave autoresize'
},
toolbar: {
type: [String, Array],
default:
// 'bold italic underline strikethrough kityformula-editor | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink image code | removeformat'
`code undo redo restoredraft | cut copy paste pastetext kityformula-editor | forecolor backcolor bold italic underline strikethrough link codesample | \
alignleft aligncenter alignright alignjustify outdent indent formatpainter | \
styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
table image media charmap hr pagebreak insertdatetime | fullscreen preview`
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: 'auto'
},
// 是否展示菜单栏
isShowMenubar: {
type: Boolean,
default: true
},
placeholder: {
type: String,
default: ''
}
},
data() {
return {
newImgUrl: [],
init: {
promotion: false, // 这个要加上,不然富文本会出现更新按钮的
branding: false, // 去掉编辑器右下角的广告
height: this.height,
width: '100%',
language: 'zh_CN', // 汉化
language_url: '/static/tinymce/langs/zh_CN.js', // 这里的地址指向 public 目录下的路径
// skin: 'oxide', // 默认值是 oxide 和skin_url配合使用
skin_url: '/static/tinymce/skins/ui/oxide', // 官方自带三种主题,gray,lightgray,flat
content_css: '/static/tinymce/skins/content/default/content.min.css', // 官方自带三种主题,gray,lightgray,flat
plugins: this.plugins, // 插件配置
toolbar: this.toolbar, // 工具栏
external_plugins: { // 外部插件
'kityformula-editor': '/static/tinymce/plugins/kityformula-editor/plugin.min.js'
},
menubar: this.isShowMenubar // 是否显示菜单栏
},
myValue: this.value
}
},
watch: {
value(newValue) {
console.log(' hj ~ file: tinymce.vue:85 ~ value ~ newValue:', newValue)
this.myValue = newValue
},
myValue(newValue) {
this.$emit('input', newValue)
}
},
methods: {}
}
</script>