点击文本将内容填入tinymce-vue 富文本编辑器的光标处

富文本编辑器组件

<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],
      // powerpaste
      default:
        '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.php
        wordlimit: {
          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 = null
          const fileSize = 3
          const 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 < fileSize
          if (!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 events
    onClick(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

  <TEditor
     id="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}`
  }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913763.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能家居的未来:AI让生活更智能还是更复杂?

内容概要 智能家居的概念源于将各种家居设备连接到互联网&#xff0c;并通过智能技术进行控制和管理。随着人工智能的迅速发展&#xff0c;这一领域也迎来了前所未有的机遇。从早期简单的遥控器到如今可以通过手机应用、语音助手甚至是环境感应进行操作的设备&#xff0c;智能…

Meta AI 新技术,赋予机器人 “触觉” 的革命

Meta AI 新技术&#xff0c;赋予机器人 “触觉” 的革命 简介 传统机器人的局限 Meta AI 的新技术突破 技术应用前景 未来展望 简介 在科技飞速发展的今天&#xff0c;人工智能领域不断取得令人惊叹的突破。11月4日&#xff0c;Meta公司宣布其基础人工智能研究团队(FAIR)在…

微信小程序配置

1.进入微信小程序公众平台&#xff0c;进入后注册域名 2.项目接口代理 UniApp H5 跨域代理配置并使用&#xff08;配置manifest.json、vue.config.js&#xff09;_uniapp 代理-CSDN博客 我用了方法一 3.测试接口

IEEE JSSC更新|Tiny Tapeout:让每个人都能设计定制芯片

简介 由于成本高昂且需要专业技术&#xff0c;设计和制造定制集成电路的传统上仅限于大型公司和机构。然而&#xff0c;名为Tiny Tapeout的创新项目正在改变这一现状&#xff0c;让业余爱好者、学生和小型团队也能设计定制芯片。本文将探讨Tiny Tapeout的工作原理&#xff0c;以…

ubuntu 22.04 server 安装 anaconda3

ubuntu 22.04 server 安装 anaconda3 https://www.anaconda.com/download/success Anaconda Installers wget https://repo.anaconda.com/archive/Anaconda3-2024.10-1-Linux-x86_64.sh 其他的是 默认 Executing transaction: done installation finished. Do you wish to…

【SpringMVC】基础入门(1)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;什么是Spring Web MVC 1&#xff1a;Servlet 2&#xff1a;总结 二&#xff1a;MVC …

【linux】网络基础 ---- 应用层

1. 再谈 "协议" 协议是一种 "约定"&#xff0c;在读写数据时, 都是按 "字符串" 的方式来发送接收的. 但是这里我们会遇到一些问题&#xff1a; 如何确保从网上读取的数据是否是完整的&#xff0c;区分缓冲区中的由不同客户端发来的数据 2. 网…

Zookeeper运维秘籍:四字命令基础、详解及业务应用全解析

文章目录 一、四字命令基础二、四字命令详解三、四字命令的开启与配置四、结合业务解读四字命令confconsenvi命令Stat命令MNTR命令ruok命令dump命令wchswchp ZooKeeper&#xff0c;作为一款分布式协调服务&#xff0c;提供了丰富的四字命令&#xff08;也称为四字短语&#xff…

MinGW-w64_10.0.0 + GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip

主题&#xff1a;mingw-w64安装 以及 matlab适配mingw-w64&#xff0c;g&#xff0c;gcc 无套路直接下载mingw-w64 for matlab 通过百度网盘分享的文件&#xff1a; MinGW-w64_10.0.0 GCC12_x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.zip 链接&#xff1a;https…

SpringCloudalibaba 集成 Knife4j 的时候出现多余的 前缀

这里是在网关 GateWay 中集成的 Knife4j&#xff0c;并且使用的是 Knife4j 服务发现模式 问题 用户服务 接口地址&#xff1a;/api/user/login GateWay 服务 现像 打开 Knife4j 文档中接口地址前缀多了一个 /api/user 解决 参考链接 2.1 Spring Cloud Gateway集成Knife4j …

信息安全工程师(79)网络安全测评概况

一、定义与目的 网络安全测评是指参照一定的标准规范要求&#xff0c;通过一系列的技术、管理方法&#xff0c;获取评估对象的网络安全状况信息&#xff0c;并对其给出相应的网络安全情况综合判定。其对象主要为信息系统的组成要素或信息系统自身。网络安全测评的目的是为了提高…

【Leecode】Leecode刷题之路第46天之全排列

题目出处 46-全排列-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 46-全排列-官方解法 预备知识 回溯法&#xff1a;一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解…

机器学习—选择激活函数

可以为神经网络中的不同神经元选择激活函数&#xff0c;我们将从如何为输出层选择它的一些指导开始&#xff0c;事实证明&#xff0c;取决于目标标签或地面真相标签y是什么&#xff0c;对于输出层的激活函数&#xff0c;将有一个相当自然的选择&#xff0c;然后看看激活函数的选…

97_api_intro_imagerecognition_pdf2word

通用 PDF OCR 到 Word API 数据接口 文件处理&#xff0c;OCR&#xff0c;PDF 高可用图像识别引擎&#xff0c;基于机器学习&#xff0c;超精准识别率。 1. 产品功能 通用识别接口&#xff1b;支持中英文等多语言字符混合识别&#xff1b;formdata 格式 PDF 文件流传参&#xf…

不适合的学习方法

文章目录 不适合的学习方法1. 纯粹死记硬背2. 过度依赖单一资料3. 线性学习4. 被动学习5. 一次性学习6. 忽视实践7. 缺乏目标导向8. 过度依赖技术9. 忽视个人学习风格10. 过于频繁的切换 结论 以下是关于不适合的学习方法的更详细描述&#xff0c;包括额外的内容和相关公式&…

刷题笔记——栈和队列互相冒充

刷题笔记——栈和队列互相冒充 5.3 用队列实现栈两队列实现栈一个队列实现栈 5.4 用栈实现队列两栈实现队列push栈和pop栈一个栈实现队列 5.3 用队列实现栈 原OJ题&#xff1a;225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 两队列实现栈 入栈的实现 选非空的…

Mysql基础 01 数据与sql

文章目录 一、基本概念二、mysql的常用命令三、sql规范四、数据类型五、SQL语句 一、基本概念 数据库(database,DB)&#xff1a;存储数据的仓库。 数据库管理系统软件(Database Management System,DBMS)&#xff1a;是一种操作和管理数据库的大型软件。常见的DBMS有oracle、s…

5G NR:各物理信道的DMRS配置

DMRS简介 在5G中&#xff0c;DMRS&#xff08;DeModulation Reference Signal&#xff09;广泛存在于各个重要的物理信道当中&#xff0c;如下行的PBCH&#xff0c;PDCCH和PDSCH&#xff0c;以及上行的PUCCH和PUSCH。其最为重要的作用就是相干解调&#xff08;Coherence Demodu…

从零开始:利用Portainer CE和cpolar搭建NextCloud私有云存储

文章目录 前言1. 在PortainerCE中创建NextCloud容器2. 公网远程访问本地NextCloud容器2.1 内网穿透工具安装3.2 创建远程连接公网地址 3. 固定NextCloud私有云盘公网地址 前言 本文将介绍如何在本地利用Portainer CE的可视化界面创建NextCloud私有云盘容器&#xff0c;并通过c…

第三十七章 Vue之编程式导航及跳转传参

目录 一、编程式导航跳转方式 1.1. path 路径跳转 1.1.1. 使用方式 1.1.2. 完整代码 1.1.2.1. main.js 1.1.2.2. App.vue 1.1.2.3. index.js 1.1.2.4. Home.vue 1.1.2.5. Search.vue 1.2. name 命名路由跳转 1.2.1. 使用方式 1.2.2. 完整代码 1.2.2.1. main.js 1…