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