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

news2024/12/26 20:42:04

富文本编辑器组件

<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}`
  }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

星海智算:风月ComfyUI_SD3.5

&#xff08;一&#xff09;镜像介绍 1、风月ComfyUI_SD3.5​ 占用69.71G磁盘&#xff0c;为用户预留了近30个G使用。 2、SD3.5​ SD3.5&#xff0c;即Stable Diffusion 3.5&#xff0c;是Stability AI推出的最新图像生成模型&#xff0c;是Stable Diffusion 3.0版本的升级版…

在模方置平建筑失败的原因是什么?

在模方置平建筑失败的原因是什么&#xff1f; 可能是obj拓扑不连续&#xff0c;可以在网格大师使用osgb转obj功能&#xff0c;选择拓扑或者重建。 网格大师是一款能够解决实景三维模型空间参考、原点、瓦块大小不统一&#xff0c;重叠区域处理问题的工具“百宝箱”&#xff0c…

python 语言入门

目录 1.发展历程 2.优缺点 3.环境搭建 3.1.Anaconda 3.2.VSCode 3.3.重装自己的独立环境 4.第一个 python 程序 4.1.创建一个 .py 的文件 4.2.编写 python 代码 ​4.3.运行 python 代码 5.注释 5.1.单行注释 5.2.多行注释 6.转义字符 7.变量 7.1.变量类型 7.2…

C++11 --- 智能指针详解

C11 智能指针 一、智能指针的使用场景分析二、RAII和智能指针的设计思路三、智能指针的本质及衍生的问题四、C标准库的智能指针的使用五、智能指针的原理&#xff08;模拟实现&#xff09;1. auto_ptr的模拟实现2. unique_ptr的模拟实现3. shared_ptr的模拟实现&#xff08;简单…

(实战)WebApi第13讲:怎么把不同表里的东西,包括同一个表里面不同的列设置成不同的实体,所有的给整合到一起?【前端+后端】、前端中点击标签后在界面中显示

一、实现全局跨域&#xff1a;新建一个Controller&#xff0c;其它的controller都继承它 1、新建BaseController 2、在后端配置&#xff0c;此处省略【详情见第12讲四、3、】 3、其它的控制器继承BaseController&#xff0c;这个时候就能够完成全局的跨域 【向后台传cookie和…

【C++】map和set的介绍及使用

前言&#xff1a; map和 set 是 C STL&#xff08;标准模板库&#xff09;中的两种非常重要的容器&#xff0c;它们基于一种叫做平衡二叉搜索树&#xff08;通常是红黑树&#xff09;的数据结构来实现。在 C 中&#xff0c;map 是一个键值对容器&#xff0c;set 只存储唯一的键…

Python的函数(补充浅拷贝和深拷贝)

一、定义 函数的定义&#xff1a;实现【特定功能】的代码块。 形参&#xff1a;函数定义时的参数&#xff0c;没有实际意义 实参&#xff1a;函数调用/使用时的参数&#xff0c;有实际意义 函数的作用&#xff1a; 简化代码提高代码重用性便于维护和修改提高代码的可扩展性…

el-input 正则表达式校验输入框不能输入汉字

<el-form :model"data1" :rules"rules" ref"ruleForm" label-width"210px" class"demo-ruleForm"><el-form-item label"锯路&#xff1a;" prop"sawKref"><el-input class"inptWid…

嵌入式linux系统中I2C控制实现AP3216C传感器方法

大家好,今天主要给大家分享一下,如何使用linux系统里面的I2C进行控制实现。 第一:Linux系统中I2C简介 Linux 内核开发者为了让驱动开发工程师在内核中方便的添加自己的 I2C 设备驱动程序,更容易的在 linux 下驱动自己的 I2C 接口硬件,进而引入了 I2C 总线框架。与 Linux 下…

OceanBase 应用实践:如何处理数据空洞,降低存储空间

问题描述 某保险行业客户的核心系统&#xff0c;从Oracle 迁移到OceanBase之后&#xff0c;发现数据存储空间出现膨胀问题&#xff0c;数据空间 datasize9857715.48M&#xff0c;实际存储占用空间17790702.00M。根据 required_mb - data_mb 值判断&#xff0c;数据空洞较为严重…

【flask开启进程,前端内容图片化并转pdf-会议签到补充】

flask开启进程,前端内容图片化并转pdf-会议签到补充 flask及flask-socketio开启threading页面内容转图片转pdf流程前端主js代码内容转图片-browser端browser端的同步编程flask的主要功能route,def 总结 用到了pdf,来回数据转发和合成,担心flask卡顿,响应差,于是刚好看到threadi…

QT栅格布局的妙用

当groupBox中只有一个控件时&#xff0c;我们想要它满格显示可以对groupBox使用栅格布局

MyBatis快速入门(上)

MyBatis快速入门&#xff08;上&#xff09; 一、MyBatis 简介1、概述2、JDBC、Hibernate、MyBatis 对比 二、MyBatis 框架搭建1、开发环境2、创建maven工程3、创建MyBatis的核心配置文件4、创建mapper接口5、创建MyBatis的映射文件6、通过junit测试功能7、加入log4j2日志功能 …

在Pybullet中加载Cinema4D创建的物体

首先明确我们的目标&#xff0c;是希望在cinema4D中创建自己想要的模型&#xff0c;并生成.obj文件&#xff0c;然后在pybullet中加载.obj文件作为静态物体&#xff0c;可以用于抓取物体&#xff0c;避障物体。&#xff08;本文提到的方法只能实现静态物体的建模&#xff0c;如…

第十三届交通运输研究(上海)论坛┆智能网联汽车技术现状与研究实践

0.简介 交通运输研究&#xff08;上海&#xff09;论坛&#xff08;简称为TRF&#xff09;是按照国际会议的组织原则&#xff0c;为综合交通运输领域学者们构建的良好合作交流平台。交通运输研究&#xff08;上海&#xff09;论坛已经成功举办了十二届&#xff0c;凝聚了全国百…

Pr:视频过渡快速参考(合集 · 2025版)

Adobe Premiere Pro 自带七组约四十多个视频过渡 Video Transitions效果&#xff0c;包含不同风格和用途&#xff0c;可在两个剪辑之间创造平滑、自然的转场&#xff0c;用来丰富时间、地点或情绪的变化。恰当地应用过渡可让观众更好地理解故事或人物。 提示&#xff1a; 点击下…

stm32 踩坑笔记

串口问题&#xff1a; 问题&#xff1a;会改变接收缓冲的下一个字节 串口的初始化如下&#xff0c;位长度选择了9位。因为要奇偶校验&#xff0c;要选择9位。但是接收有用数据只用到1个字节。 问题原因&#xff1a; 所以串口接收时会把下一个数据更改

昇思大模型平台打卡体验活动:项目4基于MindSpore实现Roberta模型Prompt Tuning

基于MindNLP的Roberta模型Prompt Tuning 本文档介绍了如何基于MindNLP进行Roberta模型的Prompt Tuning&#xff0c;主要用于GLUE基准数据集的微调。本文提供了完整的代码示例以及详细的步骤说明&#xff0c;便于理解和复现实验。 环境配置 在运行此代码前&#xff0c;请确保…

后悔没早点知道,Coze 插件 + Cursor 原来可以这样赚钱

最近智能体定制化赛道异常火爆。 打开闲鱼搜索"Coze 定制",密密麻麻的服务报价直接刷屏,即使表明看起来几十块的商家,一细聊,都是几百到上千不等的报价。 有趣的是,这些智能体定制化服务背后,最核心的不只是工作流设计,还有一个被很多人忽视的重要角色 —— …

基于STM32的节能型路灯控制系统设计

引言 本项目基于STM32微控制器设计了一个智能节能型路灯控制系统&#xff0c;通过集成多个传感器模块和控制设备&#xff0c;实现对路灯的自动调节。该系统能够根据周围环境光照强度、车辆和行人活动等情况&#xff0c;自动控制路灯的开关及亮度调节&#xff0c;从而有效减少能…