富文本编辑器组件
<template><div ref="tinymceBox" class="tinymce-box"><Editor id="myEditor" v-model="contentValue" :init="init" :disabled="disabled" @blur="inputBlur" @click="onClick" /></div>
</template><script>
const api = import.meta.env.VITE_APP_API_FILE
import { post } from '@/services/http'// 引入tinymce编辑器
import Editor from '@tinymce/tinymce-vue'// 引入node_modules里的tinymce相关文件文件
import tinymce from 'tinymce/tinymce' // tinymce默认hidden,不引入则不显示编辑器
import 'tinymce/themes/silver' // 编辑器主题,不引入则报错
import 'tinymce/icons/default' // 引入编辑器图标icon,不引入则不显示对应图标// 引入编辑器插件(基本免费插件都在这儿了)
// import 'tinymce/plugins' //高级列表
// import 'tinymce/plugins/anchor' //锚点
// import 'tinymce/plugins/autolink' //自动链接
// import 'tinymce/plugins/autoresize' //编辑器高度自适应,注:plugins里引入此插件时,Init里设置的height将失效
// import 'tinymce/plugins/autosave' //自动存稿
// import 'tinymce/plugins/charmap' //特殊字符
import 'tinymce/plugins/code' // 编辑源码
import 'tinymce/plugins/codesample' // 代码示例
import 'tinymce/plugins/directionality' // 文字方向
// import 'tinymce/plugins/emoticons' //表情
// import 'tinymce/plugins/fullpage' //文档属性
import 'tinymce/plugins/fullscreen' // 全屏
// import 'tinymce/plugins/help' //帮助
import 'tinymce/plugins/hr' // 水平分割线
import 'tinymce/plugins/image' // 插入编辑图片
// import 'tinymce/plugins/importcss' //引入css
// import 'tinymce/plugins/insertdatetime' //插入日期时间
import 'tinymce/plugins/link' // 超链接
import 'tinymce/plugins/lists' // 列表插件
import 'tinymce/plugins/media' // 插入编辑媒体
// import 'tinymce/plugins/nonbreaking' //插入不间断空格
// import 'tinymce/plugins/pagebreak' //插入分页符
// import 'tinymce/plugins/paste' //粘贴插件import 'tinymce/plugins/preview' // 预览
import 'tinymce/plugins/print' // 打印
// import 'tinymce/plugins/quickbars' //快速工具栏
// import 'tinymce/plugins/save' //保存
// import 'tinymce/plugins/searchreplace' //查找替换
// import 'tinymce/plugins/spellchecker' //拼写检查,暂未加入汉化,不建议使用
// import 'tinymce/plugins/tabfocus' //切入切出,按tab键切出编辑器,切入页面其他输入框中
import 'tinymce/plugins/table' // 表格
// import 'tinymce/plugins/template' //内容模板
// import 'tinymce/plugins/textcolor' //文字颜色
// import 'tinymce/plugins/textpattern' //快速排版
// import 'tinymce/plugins/toc' //目录生成器
import 'tinymce/plugins/visualblocks' // 显示元素范围
// import 'tinymce/plugins/visualchars' //显示不可见字符
import 'tinymce/plugins/wordcount' // 字数统计
export default {name: 'TEditor',components: {Editor},props: {value: {type: String,default: ''},disabled: {type: Boolean,default: false},plugins: {type: [String, Array],// powerpastedefault:'print code codesample preview directionality visualblocks fullscreen image link media table hr lists wordcount indent2em wordlimit'},toolbar: {type: [String, Array],// undo redo media visualblocks fontselect 隐藏工具default:'fullscreen code codesample restoredraft forecolor backcolor bold italic underline strikethrough link | formatselect fontsizeselect lineheight | alignleft aligncenter alignright alignjustify | indent2em outdent indent | bullist numlist | blockquote removeformat | table image charmap hr print preview | '},fileType: {type: String,default: ''},supportBase64: {type: Boolean,default: true},maxLimit: {type: Number,default: 500},placeholder: {type: String,default: ''}},data() {return {dom: null,init: {language_url: '/tinymce/langs/zh_CN.js', // 引入语言包文件language: 'zh_CN', // 语言类型skin_url: '/tinymce/skins/ui/oxide', // 皮肤:浅色// skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色plugins: this.plugins, // 插件配置toolbar: this.toolbar, // 工具栏配置,设为false则隐藏menubar: false, // 菜单栏配置,设为false则隐藏external_plugins: {// powerpaste: `/tinymce/powerpaste/plugin.min.js`,indent2em: `/tinymce/indent2em/plugin.min.js`,wordlimit: `/tinymce/wordlimit/plugin.min.js`},fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px', // 字体大小font_formats: `思源宋体='思源宋体';微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings`, // 字体样式lineheight_formats: '0.5 0.8 1 1.2 1.5 1.75 2 2.5 3 4 5', // 行高配置,也可配置成"12px 14px 16px 20px"这种形式// height: 400, //注:引入autoresize插件时,此属性失效min_height: 300,max_height: 500,toolbar_mode: 'sliding',placeholder: this.placeholder || '在这里输入描述',branding: false, // tiny技术支持信息是否显示resize: true, // 编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号// statusbar: false, //最下方的元素路径和字数统计那一栏是否显示elementpath: false, // 元素路径是否显示content_style: 'img {max-width:100%;} .mce-item-anchor {display:none !important}', // 直接自定义可编辑区域的css样式content_css: 'tinymce/skins/content/default/content.css', // 以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入// images_upload_url: '/apib/api-upload/uploadimg', //后端处理程序的url,建议直接自定义上传函数image_upload_handler,这个就可以不用了// images_upload_base_path: '/demo', //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.phpwordlimit: {max: this.maxLimit, // 最多可以输入多少字spaces: false, // 是否含空格isInput: false, // 是否在超出后还可以输入maxMessage: `超出最大输入字符数量,最多允许${this.maxLimit}个字符!`},setup(editor) {// 设置默认字体样式editor.on('init', function (e) {this.getBody().style.lineHeight = '2'this.getBody().style.fontFamily = '微软雅黑'})},urlconverter_callback: (url, node, onSave, name) => {if (node === 'img' && url.startsWith('blob:')) {tinymce.activeEditor && tinymce.activeEditor.uploadImages()}return url},// paste_preprocess: (editor, args) => {// if (this.disabled) {// args.content = ''// }// },end_container_on_empty_block: true,powerpaste_html_import: 'merge',powerpaste_word_import: 'merge',powerpaste_allow_local_images: true,paste_data_images: true, // 图片是否可粘贴images_upload_handler: (blobInfo, success, failure) => {let file = nullconst fileSize = 3const fileType = ['jpg', 'png']if (blobInfo.blob() instanceof Blob) {file = new File([blobInfo.blob()], blobInfo.blob().name || 'image.png', { type: 'image/png' })} else {file = blobInfo.blob()}const suffix = file.name.substring(file.name.lastIndexOf('.') + 1).toLocaleLowerCase()const allowType = fileType.map(v => v.toLocaleLowerCase()).includes(suffix)const allowSize = file.size / 1024 / 1024 < fileSizeif (!allowType) {failure('上传失败,仅支持上传JPG、PNG格式的图片')} else if (!allowSize) {failure(`上传失败,图片大小请控制在 ${fileSize}M 以内`)} else {const params = new FormData()params.append('file', file)params.append('type', this.fileType || 'product')const config = {headers: {'Content-Type': 'multipart/form-data','Client-Type': 0}}const AuthorizationInfo = localStorage.getItem('AuthorizationInfo')if (AuthorizationInfo) {const { tokenHeader, tokenHead, token } = JSON.parse(AuthorizationInfo)config.headers[tokenHeader] = `${tokenHead} ${token}`}post(api, params, config, '/').then(res => {success(res.url) // 上传成功,在成功函数里填入图片路径}).catch(() => {// 是否支持上传图片为base64格式if (!this.supportBase64) {const imgReg = /<img.*?(?:>|\/>)/gi // 匹配图片中的img标签this.contentValue = this.contentValue.replace(imgReg, (match, capture) => (match.indexOf('base64') == -1 ? match : ''))}failure('上传出错,服务器开小差了呢')})}}},contentValue: this.value}},watch: {value(newValue) {this.contentValue = newValue},contentValue(newValue) {this.$emit('input', newValue)}},mounted() {tinymce.init({})},methods: {// 添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available eventsonClick(e) {this.$emit('onClick', e, tinymce)},// 清空内容clear() {this.contentValue = ''},// 失去焦点inputBlur() {this.$emit('blur')}}
}
</script><style lang="less" scoped>
.tinymce-box {min-height: 300px;
}
</style>
项目中引用
注意:要给组件加上id
<TEditorid="myEditor"ref="tEditorRef"fileType="supply/hr/report"v-model:value="formState.emailContent"@input="e => (formState.emailContent = e)":maxLimit="10000"placeholder="请输入邮件内容"/>// 点击标签
const changeLabel = item => {const editor = tinymce.get('myEditor')if (editor) {editor.focus()editor.selection.setContent(`<div>【${item}】</div>`)}state.labelCount++if (state.labelCount <= 2) {formState.emailSubject += `【${item}】`}
}