vue後臺管理系統富文本組件(一)tinymce
簡介
富文本組件作爲後臺管理系統的最重要的基礎組件之一,一定要選擇坑比較少的富文本廠家。這裏使用的是好看又坑少的tinymce。
主要依賴說明 (先安裝,步驟略)
{
"axios": "^0.18.0",
"element-ui": "2.11.1",
"vue": "^2.6.10",
"vue-router": "^3.0.1"
}
tinymce:5.0.8 這裏直接採用下載源碼的方式,npm下載極大的影響打包速度,也可以使用cdn
正文
1.下載tinymce源碼放在vue-cli 3生成的 public文件夾下的static文件夾下 ,如圖
需要語言包的話,單獨下載zh_CN.js文件放在tinymce_5.0.8文件夾下的lang文件夾下
2.在入口html文件中導入
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<meta name="description" content="<%= webpackConfig.name %>" />
<meta name="robots" content="noindex,nofollow,noarchive" />
<title>title</title>
</head>
<body>
<script src="<%= BASE_URL %>static/tinymce_5.0.8/tinymce.min.js"></script>
<div id="app"></div>
</body>
</html>
3.組件Tinymce.vue
文件目錄
src/components/Tinymce/index.vue
<template>
<div class="tinymce-container editor-container" :class="{fullscreen:fullscreen}">
<textarea :id="tinymceId" class="tinymce-textarea" />
<div class="editor-custom-btn-container">
<multiple-upload class="editor-upload-btn" @success="imageSuccess" />
</div>
</div>
</template>
<script>
import axios from 'axios'
// MultipleUpload組件見 https://blog.csdn.net/qq_39953537/article/details/100039094
import MultipleUpload from '@/components/MultipleUpload'
import plugins from './plugins' // 見下文
import toolbar from './toolbar' // 見下文
// 上傳html片段接口根據自己項目更換
import { uploadHtml } from '@/api/upload'
export default {
name: 'Tinymce',
components: {
MultipleUpload
},
props: {
// 默認填充到富文本的html文件
html: {
type: String,
default: ''
},
toolbar: {
type: Array,
default() {
return []
}
},
menubar: {
type: Boolean,
default: false
},
height: {
type: Number,
default: 400
}
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: 'vue-tinymce-' + +new Date(),
fullscreen: false,
value: '',
editorContent: ''
}
},
watch: {
value(val) {
this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || '')
)
},
html(val) {
if (this.isUrl) {
this.loadUrl(val)
}
}
},
created() {
if (this.html && this.html.startsWith('http')) {
this.loadUrl(this.html)
} else {
this.value = this.html + ''
this.editorContent = this.html + ''
}
},
mounted() {
this.initTinymce()
},
activated() {
this.initTinymce()
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
initTinymce() {
window.tinymce.init({
fontsize_formats: '12px 14px 16px 18px 20px 24px 36px',
language: 'zh_CN',
language_url: '/static/tinymce_5.0.8/langs/zh_CN.js',
selector: `#${this.tinymceId}`,
height: this.height,
body_class: 'panel-body ',
object_resizing: true,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
default_link_target: '_blank',
link_title: false,
init_instance_callback: editor => {
if (this.value) {
editor.setContent(this.value)
}
this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
this.editorContent = editor.getContent()
})
},
setup(editor) {
editor.on('FullscreenStateChanged', e => {
this.fullscreen = e.state
})
}
})
},
destroyTinymce() {
if (window.tinymce.get(this.tinymceId)) {
window.tinymce.get(this.tinymceId).destroy()
}
},
loadUrl(url) {
if (url && url.length > 0) {
axios
.get(url)
.then(response => {
// 處理HTML顯示
this.value = response.data
this.editorContent = response.data
this.$emit('subLoadUrlToHtml', response.data)
this.$emit('input', response.data)
})
.catch(() => {
this.value = '服務器數據加載失敗,請重試!'
})
}
},
// 設置編輯器內容
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
// 獲取編輯器內容
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
// 圖片上傳成功後填充到富文本編輯器
async imageSuccess(urlList) {
try {
let imageTemplateList = ''
urlList.forEach(item => {
const image = `<img style="max-width:100%;" src="${item}">`
imageTemplateList = imageTemplateList + image
})
window.tinymce.get(this.tinymceId).insertContent(imageTemplateList)
this.$message({
message: '上傳成功!',
type: 'success'
})
} catch (error) {
console.log(error)
this.$message({
message: error,
type: 'error'
})
}
},
// 編輯器內容上傳到cos,調用返回url
async content2Url() {
try {
const res = await uploadHtml(this.editorContent)
return res
} catch (error) {
this.$message({
message: error.data.message,
type: 'error'
})
}
}
}
}
</script>
<style lang='scss' >
#tinymce {
background-color: blue;
p {
margin: 0;
}
}
.tinymce-container {
position: relative;
}
.tinymce-container >>> .mce-fullscreen {
z-index: 10000;
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
// 隱藏底部logo欄
.mce-edit-area + .mce-statusbar {
opacity: 0;
height: 0;
}
</style>
src/components/Tinymce/plugins.js
const plugins = [
'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount paste'
]
export default plugins
src/components/Tinymce/toolbar.js
const toolbar = ['formatselect fontsizeselect forecolor backcolor bold italic underline strikethrough alignleft aligncenter alignright outdent indent removeformat hr undo redo']
export default toolbar
4.使用
<template>
<div>
<tinymce
ref="tinymce"
:height="500"
:html="html"
@input="getContent"
/>
</div>
</template>
<script>
import AppCropper from '@/components/Cropper'
export default {
name: 'GoodsForm',
components: {
AppCropper
},
data() {
return {
html: 'https://ebusiness-1255313385.cosbj.myqcloud.com/image/20190823/center2019082304054532.html',
content:''
}
},
methods: {
// 獲取編輯器內容
getContent(content) {
this.content = content
},
// 編輯器內容轉換成在線url
async getcontent2Url() {
try {
const htmlUrl = await this.$refs.tinymce.content2Url()
return htmlUrl
} catch (error) {
console.log(error)
}
}
}
}
</script>
5.使用效果
參考鏈接
1.https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/Tinymce/index.vue