前端vue-TinyMCE富文本编辑器表情插件报错解决
最近项目中需要使用文本编辑器,比较了下最终选择了TinyMCE这款富文本编辑器。
我安装的是TinyMCE v5但是在使用表情插件的时候,表情一直都出不来,报错信息如下:
Uncaught SyntaxError: Unexpected token '<' Failed to load emoticons: Script at URL "http://xxxx/static/js/plugins/emoticons/js/emojis.js" did not call `tinymce.Resource.add('tinymce.plugins.emoticons', data)` within 1 second
这个是路径出问题了,导致emojis.js没有被正确导入,所以表情也就没有出来。
我们只在用到TinyMce富文本编辑器的组件中,引入表情emojis.js文件即可。
代码是这段。
import 'tinymce/plugins/emoticons/js/emojis';
在我的项目中是有TinyMce的文件夹。
我在src目录下有一个公共组件文件夹components,在这个文件夹下面有一个封装的富文本编辑器组件。看代码----------------------------------
这是HTML部分
<template> <div class="tinymce-editor"> <editor v-if="!reloading" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick"> </editor> </div> </template>
这是js部分
<script> import tinymce from 'tinymce/tinymce' import Editor from '@tinymce/tinymce-vue' import 'tinymce/themes/silver/theme' import 'tinymce/plugins/image' import 'tinymce/plugins/link' import 'tinymce/plugins/media' 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 'tinymce/plugins/fullscreen' import 'tinymce/icons/default' import 'tinymce/plugins/emoticons' import "../../../public/tinymce/plugins/media" /*不显示占位图片的插件*/ import "tinymce/plugins/preview" import "tinymce/plugins/code" import "tinymce/plugins/insertdatetime" import "tinymce/plugins/template" import 'tinymce/plugins/emoticons/js/emojis'; import { uploadAction,getFileAccessHttpUrl } from '@/api/manage' import { getVmParentByName } from '@/utils/util' export default { components: { Editor }, props: { value: { type: String, required:false }, triggerChange:{ type: Boolean, default: false, required:false }, disabled: { type: Boolean, default: false }, plugins: { type: [String, Array], default: 'lists image link media table textcolor wordcount contextmenu fullscreen emoticons preview code insertdatetime ' }, toolbar: { type: [String, Array], default: 'undo redo | formatselect | bold italic forecolor backcolor | fontsizeselect | code | emoticons | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link unlink image media table | insertdatetime | removeformat| preview | fullscreen ', branding:false } }, data() { return { //初始化配置 init: { language_url: '/tinymce/langs/zh_CN.js', language: 'zh_CN', skin_url: '/tinymce/skins/ui/oxide', height: 150, plugins: this.plugins, toolbar: this.toolbar, branding: false, menubar: false, toolbar_drawer: false, auto_focus : true, file_picker_callback:'media', file_picker_types:'media', images_upload_handler: (blobInfo, success) => { let formData = new FormData() formData.append('file', blobInfo.blob(), blobInfo.filename()); formData.append('biz', "jeditor"); formData.append("jeditor","1"); uploadAction(window._CONFIG['domianURL']+"/sys/common/upload", formData).then((res) => { if (res.success) { if(res.message == 'local'){ const img = 'data:image/jpeg;base64,' + blobInfo.base64() success(img) }else{ let img = getFileAccessHttpUrl(res.message) success(img) } } }) }, }, myValue: this.value, reloading: false, } }, mounted() { this.initATabsChangeAutoReload() }, methods: { file_picker_callback: function (cb, value, meta) { if (meta.filetype === 'media'){ //模拟上传视频 let input = document.createElement('input') input.setAttribute('type','file') input.onchange = function (){ let file = this.files[0] _this.uploadMv(file) if(_this.uploaded){ cb(_this.mvUrl) }else { setTimeout(()=>{ //设置几秒之后再取数据 cb(_this.mvUrl) },1000) } } //触发点击 input.click() } }, uploadMv(file){ let content = file; let formData = new FormData(); formData.append('mv',content); }, reload() { this.reloading = true this.$nextTick(() => this.reloading = false) }, onClick(e) { this.$emit('onClick', e, tinymce) }, //可以添加一些自己的自定义事件,如清空内容 clear() { this.myValue = '' }, /** * 自动判断父级是否是 <a-tabs/> 组件,然后添加事件监听,自动触发reload() * * 由于 tabs 组件切换会导致 tinymce 无法输入, * 只有重新加载才能使用(无论是vue版的还是jQuery版tinymce都有这个通病) */ initATabsChangeAutoReload() { // 获取父级 let tabs = getVmParentByName(this, 'ATabs') let tabPane = getVmParentByName(this, 'ATabPane') if (tabs && tabPane) { // 用户自定义的 key let currentKey = tabPane.$vnode.key // 添加事件监听 tabs.$on('change', (key) => { // 切换到自己时执行reload if (currentKey === key) { this.reload() } }) //update--begin--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------ this.reload() //update--end--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------ }else{ //update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------ let tabLayout = getVmParentByName(this, 'TabLayout') //update--begin--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------ try { tabLayout.excuteCallback(() => { this.reload() }) } catch (error) { if (tabLayout) { this.reload() } } //update--end--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------ //update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------ } }, }, watch: { value(newValue) { this.myValue = (newValue == null ? '' : newValue) }, myValue(newValue) { if(this.triggerChange){ this.$emit('change', newValue) }else{ this.$emit('input', newValue) } } } } </script>
这就是封装好的tinyMce,里面包含了,你会用到的所有的功能,对你有帮助的话,不妨点个赞吧。谢谢啦!!!
如果还有哪里不太懂的记得关注私信我。