本文主要講的是在
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> 複製代碼