本文主要讲的是在
Vue cli 3
脚手架搭建的项目里如何引用Tinymce 5
富文本编辑器。css
请注意识别“版本号”,不一样版本的配置细节有所不一样。 vue
npm install @tinymce/tinymce-vue -S
复制代码
npm install tinymce -S
复制代码
tinymce提供的语言包不少,选择下载中文语言包node
public
目录下新建tinymce
文件夹,将下载的中文语言包解压后放在该文件夹下node_modules
里找到tinymce
文件夹,将里面的skins
文件夹复制到public/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' 复制代码
注册组件git
components: { Editor }
复制代码
使用组件github
<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” } 复制代码
<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> 复制代码
简单封装一下,方便使用npm
<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示例api
<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> 复制代码