在vue cli 3脚手架里引入tinymce 5富文本编辑器
本文主要讲的是在
Vue cli 3
脚手架搭建的项目里如何引用Tinymce 5
富文本编辑器。
请注意识别“版本号”,不同版本的配置细节有所不同。
tinymce的安装
安装tinymce-vue
npm install @tinymce/tinymce-vue -S
安装tinymce
npm install tinymce -S
下载中文语言包
tinymce提供的语言包很多,选择下载中文语言包
使用方法
文件操作
- 在项目根目录的
public
目录下新建tinymce
文件夹,将下载的中文语言包解压后放在该文件夹下 - 在依赖包
node_modules
里找到tinymce
文件夹,将里面的skins
文件夹复制到public/tinymce
目录下
目录截图
tinymce初始化
引入基本文件
// 引入组件
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
// 引入富文本编辑器主题的js和css
import 'tinymce/themes/silver/theme.min.js'
import 'tinymce/skins/ui/oxide/skin.min.css'
// 扩展插件
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
注册组件并使用
注册组件
components: { Editor }
使用组件
<Editor id="tinymce" v-model="tinymceHtml" :init="editorInit" />
初始化配置项
editorInit: {
selector: '#tinymce',
language_url: '/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/tinymce/skins/ui/oxide',
height: 300,
plugins: 'link lists image code table wordcount',
toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink image code | removeformat',
images_upload_handler: (blobInfo, success, failure) => {
this.handleImgUpload(blobInfo, success, failure)
},
statusbar: true // 底部的状态栏
menubar: true, // 最上方的菜单
branding: false // 水印“Powered by TinyMCE”
}
简单demo
<template>
<div class="activeConfig">
<div class="activeConfig-container">
<Editor id="tinymce" v-model="tinymceHtml" :init="editorInit" />
</div>
</div>
</template>
<script>
// 引入组件
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
// 引入富文本编辑器主题的js和css
import 'tinymce/themes/silver/theme.min.js'
import 'tinymce/skins/ui/oxide/skin.min.css'
// 扩展插件
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
// 引入api
import { uploadImgage } from '@/api/activeConfig'
export default {
name: 'ActiveConfig',
components: { Editor },
data() {
return {
// tinymce的绑定值
tinymceHtml: '',
// tinymce的初始化配置
editorInit: {
selector: '#tinymce',
language_url: '/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/tinymce/skins/ui/oxide',
height: 300,
plugins: 'link lists image code table wordcount',
toolbar: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink image code | removeformat',
// 此处为图片上传处理函数
images_upload_handler: (blobInfo, success, failure) => {
this.handleImgUpload(blobInfo, success, failure)
},
statusbar: true // 底部的状态栏
menubar: true, // 最上方的菜单
branding: false // 水印“Powered by TinyMCE”
}
}
},
mounted() {
tinymce.init({})
},
methods: {
// 图片上传
handleImgUpload(blobInfo, success, failure) {
this.baseUrl = process.env.VUE_APP_BASE_URL
const imgBase64 = `data:${blobInfo.blob().type};base64,${blobInfo.base64()}`
const data = { img: [imgBase64] }
uploadImgage(data).then(res => {
// 传入success回调里的数据就是富文本编辑器里插入图片的src的值
success(`${this.baseUrl}/${res.data[0]}`)
}).catch(() => { failure('error') })
}
}
}
</script>
<style lang="scss" scoped>
.activeConfig {
&-container {
margin: 30px;
}
}
</style>
封装组件
简单封装一下,方便使用
<template>
<div class="tinymce-editor">
<Editor
:id="editorId"
v-model="editorValue"
:init="editorInit"
:disabled="disabled"
@onClick="handleClick"
/>
</div>
</template>
<script>
// 引入组件
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
// 引入富文本编辑器主题的js和css
import 'tinymce/themes/silver/theme.min.js'
import 'tinymce/skins/ui/oxide/skin.min.css'
// 扩展插件
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount' // 字数统计插件
export default {
name: 'TinymceEditor'
components: { Editor },
props: {
id: {
type: String,
default: 'tinymceEditor'
},
value: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default: 'link lists image code table wordcount'
},
toolbar: {
type: [String, Array],
default: 'bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent blockquote | undo redo | link unlink image code | removeformat'
}
},
data() {
return {
editorInit: {
language_url: '/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/tinymce/skins/ui/oxide',
height: 300,
plugins: this.plugins,
toolbar: this.toolbar,
statusbar: true, // 底部的状态栏
menubar: true, // 最上方的菜单
branding: false, // 水印“Powered by TinyMCE”
images_upload_handler: (blobInfo, success, failure) => {
this.$emit('handleImgUpload', blobInfo, success, failure)
}
},
editorId: this.id,
editorValue: this.value
}
},
watch: {
editorValue(newValue) {
this.$emit('input', newValue)
}
},
mounted() {
tinymce.init({})
},
methods: {
// https://github.com/tinymce/tinymce-vue => All available events
handleClick(e) {
this.$emit('onClick', e, tinymce)
},
clear() {
this.editorValue = ''
}
}
}
</script>
封装组件后demo
使用组件的完整demo示例
<template>
<div class="demo">
<tinymce-editor
:id="editorId"
ref="editor"
v-model="message"
:disabled="isEditorDisabled"
@input="handleInput"
@onClick="handleClick"
@handleImgUpload="imgUpload"
/>
<div class="demo-btn">
<el-button type="primary" @click="clearClick">清空内容</el-button>
<el-button @click="disableClick">{{ !isEditorDisabled ? '禁用' : '启用' }}</el-button>
</div>
</div>
</template>
<script>
import TinymceEditor from '@/components/TinymceEditor'
export default {
components: { TinymceEditor },
data() {
return {
message: '我经常被生活锤得心灰意冷,可我从来都没放弃过。',
editorId: 'editor-demo',
isEditorDisabled: false
}
},
methods: {
// 输入事件
handleInput(value) {
console.log(value)
},
// 点击事件
handleClick(e, editor) {
console.log(e, editor)
},
// 上传图片
imgUpload(blobInfo, success, failure) {
const imgBase64 = `data:${blobInfo.blob().type};base64,${blobInfo.base64()}`
success(imgBase64)
},
// 清空事件
clearClick() {
this.$refs.editor.clear()
},
// 禁用事件
disableClick() {
this.isEditorDisabled = !this.isEditorDisabled
}
}
}
</script>
<style lang="scss" scoped>
.demo {
margin: 30px;
&-btn {
text-align: center;
margin: 10px;
}
}
</style>