<template> <div class="dee-editor"> <editor :id="tinymceId" :key="editorKey" :init="editorInit" :value="cloneValue" :disabled="disabled" /> <el-upload ref="imageUpload" action="" :http-request="uploadImage" :before-upload="beforeUpload" style="display: none" /> <!-- 特殊符号 --> <dee-dialog v-el-drag-dialog :dialog-visible="symbolDialog" width="60%" title="特殊符号" @handleClose="dialogCancles"> <!-- <symbol-page @getDom="getSymbol" /> --> <dee-symbol-tabs ref="symbolTabs" @loading="loadingFun" /> <div slot="footer" style="text-align: center;"> <!-- <el-button type="primary" size="small" @click="addSymbol">确 定</el-button> --> <!-- <el-button type="primary" size="small" @click="generateSymbol">预 览</el-button> --> <el-button type="primary" size="small" :loading="loadingSave" @click="saveSymbol">确 定</el-button> <el-button size="small" @click="dialogCancles">取 消</el-button> </div> </dee-dialog> </div> </template> <script> import 'tinymce/skins/ui/oxide/skin.min.css' // 富文本样式 import 'tinymce/skins/ui/oxide/content.min.css' // 富文本样式 import tinymce from 'tinymce/tinymce' // 配置富文本 import 'tinymce/themes/silver/theme.min.js' // 引入富文本的主要脚本 import 'tinymce/icons/default' import 'tinymce/plugins/image' import 'tinymce/plugins/fullscreen' import 'tinymce/plugins/link' import 'tinymce/plugins/code' import 'tinymce/plugins/table' import 'tinymce/plugins/lists' import 'tinymce/plugins/contextmenu' import 'tinymce/plugins/wordcount' import 'tinymce/plugins/colorpicker' import 'tinymce/plugins/textcolor' import Editor from '@tinymce/tinymce-vue' // 引用富文本组件 import DeeSymbolTabs from './DeeSymbolTabs' import { post } from '@/utils/http' import { getBucketByAppID, downloadFileById } from '@/api/file' export default { components: { Editor, DeeSymbolTabs }, props: { value: { type: String, default: () => '' }, disabled: { type: Boolean, default: false }, appId: { type: [Number, String], default: '' } }, data() { return { cloneValue: '', editorKey: 0, tinymceId: 'a' + this.$utils.GenNonDuplicateID(10), uploadData: { url: '/dfs/fileManager/feign/uploadFile' }, symbolDialog: false, symbol: '', // 特殊符号当前点击的富文本编辑器 currentEditor: '', loadingSave: false, editting: false } }, computed: { editorInit() { const that = this return { language_url: 'tinymce/langs/zh_CN.js', language: 'zh_CN', skin_url: '/tinymce/skins/ui/oxide/', height: 500, content_css: '/tinymce/skins/ui/oxide/content.min.css', statusbar: false, plugins: this.disabled ? '' : 'link lists image code table colorpicker textcolor wordcount contextmenu fullscreen', toolbar: this.disabled ? '' : 'fontselect fontsizeselect forecolor backcolor bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | imageUpload quicklink blockquote table numlist bullist preview fullscreen specialSymbol', setup: (editor) => { editor.on('init', function(e) { this.setContent(that.cloneValue || '') // this 指向 tinymce 编译器 }) editor.on('input change undo redo execCommand KeyUp', function(e) { if (editor.getContent() === that.tmp) { return } that.tmp = editor.getContent() that.editting = true setTimeout(() => { that.editting = false }, 500) that.$emit('input', that.tmp) }) editor.ui.registry.addButton('imageUpload', { tooltip: '插入图片', icon: 'image', onAction: () => { const upload = that.$refs['imageUpload'] upload.$refs['upload-inner'].handleClick() } }) editor.ui.registry.addButton('specialSymbol', { text: '特殊符号', // tooltip: '', // icon: 'image', onAction: () => { that.currentEditor = editor that.symbolDialog = true that.initSymbolTabs() editor.execCommand('selectAll') editor.selection.getRng().collapse(false) editor.focus() } }) } } } }, watch: { value(val) { if (this.editting && this.cloneValue) { return } if (val) { this.cloneValue = this.imgSrcReplace(val) } else { this.cloneValue = '' } const ed = tinymce.get(this.tinymceId) if (ed && ed.isNotDirty) { ed.insertContent(this.cloneValue) } } }, mounted() { this.cloneValue = this.imgSrcReplace(this.value) if (!tinymce.get(this.tinymceId)) { tinymce.init({}) } }, activated() { this.editorKey++ }, methods: { imgSrcReplace(htmlstr) { let regex3 = new RegExp(/token=[\w|.]+/gi) const htmlstr1 = htmlstr.replace(regex3, function(match, capture) { return 'token=' + localStorage.getItem('token') }) regex3 = null return htmlstr1 }, uploadImage(file) { const formData = new FormData() formData.append('file', file.file) formData.append('domainName', 'test') const url = '/dfs/fileManager/feign/uploadFile' getBucketByAppID({ appId: this.appId }).then(res => { formData.append('bucketId', res.items.id) post(url, formData).then(res => { if (res.items) { downloadFileById(res.items.id).then(res => { if (res.items.fileBase64) { const src = `${window.URL.createObjectURL(new Blob([this.base64ToUint8Array(res.items.fileBase64)]))}` tinymce.execCommand('mceInsertContent', true, `<img style="width:100%" src=${src}>`) } }) } }) }) }, base64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4) const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/') const rawData = window.atob(base64) const outputArray = new Uint8Array(rawData.length) for (var i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } return outputArray }, beforeUpload(file) { if (!file.type.includes('image/')) { this.$message.error('请输入图片') return false } }, // 特殊符号相关 dialogCancles() { this.symbolDialog = false this.symbol = '' }, getSymbol(val) { this.symbol = val.currentTarget }, addSymbol() { if (this.symbol) { // this.$emit('getSymbol', this.symbol) // tinymce.activeEditor.selection.setContent(`<p style='display: inline-block;'>${this.symbol.innerHTML}</p>`) tinymce.activeEditor.selection.setContent(`${this.symbol.innerHTML}`) tinymce.activeEditor.insertContent(`<span> </span>`) // tinymce.activeEditor.execCommand('') this.dialogCancles() } else { this.$utils.showMessageWarning('请选择符号') } }, // 生成符号图标 generateSymbol() { this.$refs.symbolTabs.generateSymbol() }, // 将生成的预览符号保存到富文本编辑器中 blobToDataURI(blob, callback) { var reader = new FileReader() reader.readAsDataURL(blob) reader.onload = function(e) { callback(e.target.result) } }, saveSymbol() { if (this.$refs.symbolTabs.formValid) { const fileBlob = this.$refs.symbolTabs.fileBlob const currentEditor = this.currentEditor if (fileBlob) { this.blobToDataURI(fileBlob, function(result) { // tinymce.activeEditor.selection.setContent(`<img src='${result}' alt='' width='70' height='40'>`) currentEditor.insertContent(`<img src='${result}' alt=''>`) }) this.dialogCancles() } else { this.$utils.showMessageWarning('请先选填数据生成符号!') } } else { this.$utils.showMessageWarning('请先选填相关数据生成符号!') } }, initSymbolTabs() { if (this.$refs.symbolTabs) { this.$refs.symbolTabs.initSymbolTabs() } }, loadingFun(x) { this.loadingSave = x }, // 全屏设置 toggleFullScreen(eleId) { if (this.canFullScreen) { if (this.isFullScreen) { // 关闭全屏 this.exitFullScreen() this.isFullScreen = false } else { // 打开全屏 this.requestFullScreen(document.getElementById(eleId).parentElement) this.isFullScreen = true } } else { this.$message.warning({ content: '当前浏览器暂不支持全屏模式,请切换浏览器后重新尝试!', duration: 3 }) } }, requestFullScreen(element) { // 判断各种浏览器,找到正确的方法 const requestMethod = element.requestFullScreen || // W3C element.webkitRequestFullScreen || // Chrome, safari element.mozRequestFullScreen || // FireFox element.msRequestFullscreen // IE11 if (requestMethod) { requestMethod.call(element) } }, exitFullScreen() { var exitMethod = document.exitFullscreen || // W3C document.mozCancelFullScreen || // FireFox document.webkitExitFullscreen || // Chrome等 document.msExitFullscreen // IE11 if (exitMethod) { exitMethod.call(document) } }, addFullScreenListener() { const self = this document.onkeydown = function(e) { if (e && e.keyCode === 122) { // 捕捉F11键盘动作 e.preventDefault() // 阻止F11默认动作 self.toggleFullScreen() } } // 监听不同浏览器的全屏事件,并件执行相应的代码 switch (self.browserKernel) { case 'webkit': document.onwebkitfullscreenchange = function() { if (document.webkitIsFullScreen) { self.isFullScreen = true } else { self.isFullScreen = false } } break case 'gecko': document.onmozfullscreenchange = function() { if (document.mozFullScreen) { self.isFullScreen = true } else { self.isFullScreen = false } } break case 'trident': document.onmsfullscreenchange = function() { if (document.msFullscreenElement) { self.isFullScreen = true } else { self.isFullScreen = false } } break case 'others': document.onfullscreenchange = function() { if (document.fullscreen) { self.isFullScreen = true } else { self.isFullScreen = false } } break default: break } } } } </script> <style lang="scss"> .dee-editor{ padding-top: 10px; } </style>