最近項目中需要使用文本編輯器,比較了下最終選擇了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,里面包含了,你會用到的所有的功能,對你有幫助的話,不妨點個贊吧。謝謝啦!!!
如果還有哪里不太懂的記得關注私信我。