Vue3使用tinymce的配置和坑

一、安装依赖

    1. 下载安装依赖
yarn add tinymce -S;
yarn add @tinymce/tinymce-vue -S;
    1. 下载中文语言包和静态文件
    • 2.1 这一步网上都有,直接去官网下载语言包,将文件放在public/tinymce/langs中,这样打包后静态文件会被复制到打包后的目录中
    • 2.2 还可以添加主题UI等样式,public/tinymce/skins,可以在github找一些相关项目复制下来,可选项

二、 封装组件

    1. tinymce 引入功能
    // component/Editor/js/importTinymce.js
    // 引入node_modules里的tinymce相关文件文件
    // eslint-disable-next-line no-unused-varsimport 'tinymce/themes/silver' // 编辑器主题,不引入则报错
    import 'tinymce/icons/default' // 引入编辑器图标icon,不引入则不显示对应图标
    // import 'tinymce/skins/ui/oxide/content.css'
    // import 'tinymce/skins/content/default/content.css'
    // // 引入编辑器插件(基本免费插件都在这儿了)
    import 'tinymce/plugins/advlist' // 高级列表
    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/index' // 文档属性
    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' // 字数统计
    
    1. tinymce 配置项
    // component/Editor/js/config.js
    //  导入插件
    const buttonPlugins = 'emoticons preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave paste';// 导入工具栏
    const toolbar = 'fullscreen undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor \ table image | alignleft aligncenter alignright alignjustify outdent indent | \ styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | media charmap emoticons hr pagebreak insertdatetime print preview | code selectall searchreplace visualblocks | indent2em lineheight formatpainter axupimgs';// 初始化配置
    export const init = {selector: '#js_tinymce_editor',height: 550,width: '100%',cleanup: true,language_url: './tinymce/langs/zh-Hans.js', // 引入语言包文件language: 'zh-Hans', // 语言类型content_css: true,skin_url: './tinymce/skins/ui/oxide', // 皮肤:浅色// skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色plugins: buttonPlugins, // 插件配置toolbar: toolbar, // 工具栏配置,设为false则隐藏body_class: 'panel-body',object_resizing: false, // 图片和表格是否开启在编辑器内部缩放// menubar: false, // 菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”//emoticons_database_url: './tinymce/emoticons/js/emojis.js',fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px', // 字体大小nonbreaking_force_tab: true, // 此选项允许您在用户按下键盘tab键时强制TinyMCE插入三个实体font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;', // 字体样式 微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif, 宋体=simsun,serif,仿宋体=FangSong,黑体=SimHei,Arial=arial,lineheight_formats: '0.5 0.8 1 1.2 1.5 1.75 2 2.5 3 4 5', // 行高配置,也可配置成"12px 14px 16px 20px"这种形式branding: false, // tiny技术支持信息是否显示resize: false, // 编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号// statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示elementpath: false, // 元素路径是否显示content_style: 'p {margin-block-start: 0; margin-block-end: 0; color: #606D81; font-size: 14px;}; table { border: 1px}', // 直接自定义可编辑区域的css样式// content_css: './tinymce/index.css', // 以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入paste_data_images: true, // 图片是否可粘贴images_upload_handler: (blobInfo, success, failure) => {// 需要在setup里面重新写,传入 url},imagetools_toolbar: 'editimage', // 图片控制的工具栏
    }
    
    1. tinymce 封装组件
    // components/Editor/index
    <template><div class="tinymce-box"><Editorv-model="editorContent":init="initData":disabled="isDisabled"ref="editorRef"id="js_tinymce_editor"></Editor></div>
    </template><script setup lang="ts">import Editor from '@tinymce/tinymce-vue';import tinymce from 'tinymce/tinymce'; // tinymce默认hidden,不引入则不显示编辑器import { formatTime } from '@/utils/';import { uploadImage } from '@/api/tinymce';const props = defineProps({modelValue: {type: String,default: '',},});// 导入配置文件import './js/importTinymce';import { init } from './js/config';import axios from 'axios';onMounted(() => {// 配置信息tinymce.init({});});const isDisabled = ref(true);// 初始化配置const initData = ref(Object.assign({}, init, {init_instance_callback: (editor: any) => {// 初始化编辑器实例时要执行的函数isDisabled.value = false;},// 图片上传images_upload_handler: async (blobInfo: any, success: any, failure: any) => {var form = new FormData();form.append('file', blobInfo.blob());const config = {headers: {'Content-Type': 'multipart/form-data',},};axios.post('/my-api/vueadmin/image/upload', form, config).then((res) => {const data = res.data.data;if (res.data.code === '00000') {success(data.imgUrl);} else {failure('上传失败!');}}).catch((err) => {failure('上传失败!');});},}));const editorContent = ref(props.modelValue);const emit = defineEmits(['update:modelValue']);// 实时监听内容变化,并同步到父组件watch(() => editorContent.value,(n) => {debounce(() => {emit('update:modelValue', editorContent.value);});});const timeout = ref();// 防抖const debounce = (fn: any, wait = 400) => {if (timeout.value) {clearTimeout(timeout.value);fn();}timeout.value = setTimeout(fn, wait);};
    </script><style lang="scss" scoped>.tinymce-box {width: 100%;}
    </style>

三、引用组件

    1. 封装好Tinymce组件后,可以开始应用
      注意:如果Tinymce引入的页面是弹窗之类的,存在其自身弹窗层级问题,导致其自身层级低于项目弹窗的层级,这里可以通过加添或修改public/tinymce/skins自定义的样式来覆盖
    // views/page/edit/index.js
    <!-- @format --><template><el-card><el-formref="formDataRef":model="formData":rules="rules"label-width="120px"class="demo-formData"status-icon><el-form-item label="短信内容" prop="region" style="width: 100%"><Editorv-if="editDataLoading"v-model="formData.textarea"style="width: 100%"></Editor></el-form-item></el-form><div class="btn-box"><el-button type="primary" @click="submitForm(formDataRef)"> 保存 </el-button><el-button @click="resetForm(formDataRef)">重置</el-button></div></el-card>
    </template><script setup lang="ts">import Editor from '@/components/Editor/index.vue';import type { FormInstance, FormRules } from 'element-plus';import { IFormData } from '@/api/sms/types';import { getSmsInfo, saveSms } from '@/api/sms/';const propsData = defineProps({drawerData: {type: Object,default: () => {id: '';},},});const emit = defineEmits(['closeDrawerHandle']);const editDataLoading = ref(false);const initHandle = async () => {if (propsData.drawerData?.id) {const { code, data } = await getSmsInfo(propsData.drawerData.id);if (code === '00000') {console.log(data);formData.textarea = data.textarea;formData.id = data.id;}}nextTick(() => {editDataLoading.value = true;});};initHandle();const formDataRef = ref<FormInstance>();const formData = reactive<IFormData>({textarea: '',id: '',});const rules = reactive<FormRules<IFormData>>({textarea: [{required: true,message: '请输入富文本',trigger: 'blur',},],});const submitForm = (formEl: FormInstance | undefined) => {if (!formEl) return;formEl.validate(async (valid, fields) => {if (valid) {console.log(formData);const { code, data } = await saveSms(formData);if (code === '00000') {ElMessage.success(data.msg || '保存成功!');emit('closeDrawerHandle', true);}} else {console.log(fields);ElMessage.error('保存失败!');}});};const resetForm = (formEl: FormInstance | undefined) => {if (!formEl) return;formEl.resetFields();};
    </script><style scoped></style>
    

本地虚拟机wamp存储富文本

    1. 在数据库中创建数据表
    DROP TABLE IF EXISTS `tinymce_content`;
    CREATE TABLE `tinymce_content`  (`id` bigint NOT NULL AUTO_INCREMENT,`textarea` longtext NOT NULL DEFAULT '' COMMENT '富文本内容',`create_time` date NOT NULL DEFAULT '' COMMENT '添加时间',PRIMARY KEY (`id`) USING BTREE,
    ) ENGINE = InnoDB AUTO_INCREMENT = 0 CHARACTER SET = utf8;
    
    1. 在数据库中创建图片数据表
    DROP TABLE IF EXISTS `tinymce_img`;
    CREATE TABLE `tinymce_img`  (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(100) NOT NULL DEFAULT '' COMMENT '图片名称',`url` varchar(100) NOT NULL DEFAULT '' COMMENT '图片地址',`type` varchar(50) NOT NULL DEFAULT '' COMMENT '图片类型',`blob` mediumblob DEFAULT NULL COMMENT '图片内容(不建议将图片存入数据库)',`create_time` date NOT NULL DEFAULT '' COMMENT '添加时间',PRIMARY KEY (`id`) USING BTREE,
    ) ENGINE = InnoDB AUTO_INCREMENT = 0 CHARACTER SET = utf8;
    
    1. 创建好这两张表后,在富文本编辑器中便可以将上传、截图、图片链接源存在项目中,并将图片链接存在tinymce_img中,整个内容存在tinymce_content中
    1. 后端使用PHP框架Yii2,所以图片存在根目录的/web/static/静态目录中,访问地址:http://myproject.com/static/1705046024_finmart.png,主域名是通过wamp配置的代理host访问
    1. PHP存储代码
// /controllers/TinymceImgContent.php
<?phpnamespace app\controllers;use Yii;
use app\models\TinymceImg; // 链接tinymce_img数据库的文件,里面也继承了一些封装的基类,如getDbAll()、create()
use app\controllers\BaseController; //封装一些基类,如responseclass ImageController extends BaseController
{public function actionIndex(){return $this->render('index');}public function actionUpload(){$model = new Images();// $_FILES 获取文件信息$fileData = $_FILES['file'];// 上传文件的临时路径$tempFile = $fileData['tmp_name'];// 上传文件的类型$fileType = $fileData['type'];// 尺寸大小$size = $fileData['size'];// 名称$name = time() . '_' . $fileData["name"];// dd($fileData);// 是否上传的文件if (is_uploaded_file($tempFile)) {// 从临时文件中读取内容$img = file_get_contents($tempFile);// Yii::$app->getBasePath() 项目的根目录,设置绝对访问地址$saveLocalUrl = Yii::$app->getBasePath() . "/web/static/" . $name;$imgLink = 'http://' . $_SERVER['HTTP_HOST'] . "/static/$name";// move_uploaded_file 将文件存在本地web/static中move_uploaded_file($tempFile, $saveLocalUrl);$data = [// "img"  => $img, // 存储在数据库,不建议"date" => date("Y-m-d H:i:s"),"name" => $name,"url"  => $imgLink,"type" => $fileType,];$row = $model->create($data);if (isset($row)) {$res = ['imgUrl' => $imgLink];return $this->response($res);} else {$this->code = "00001";$this->msg = "图片保存失败";return $this->response();}}}}

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

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

相关文章

ECharts 多季度连续显示到一个图中。

效果图 二.相关option 以下option可以复制到 echarts的编辑器 进行查看修改 const site test1; const site2 test2;const qtrlyOption function (data: any, titleText: string): any {//获取最大值 。最大最小值的目的是&#xff1a;使左右里边的所有bar使用同一个指标let …

[HTML]Web前端开发技术12(HTML5、CSS3、JavaScript )——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

WebGIS招聘原来看重什么?整理了1300多份岗位得出来的干货!

之前给大家分享了一份boss直聘、猎聘和前程无忧上WebGIS相关的岗位汇总表&#xff1a; http://t.csdnimg.cn/35vn4 可以直接一键投递&#xff0c;需要的宝子记得后台找我。 今天给大家汇总了这些所有岗位的要求&#xff0c;包括学历、工作经验、城市、薪资以及技术要求等。 到…

DNS从入门到精通

DNS从入门到精通 Dns从入门到精通 DNS从入门到精通一、DNS原理二、企业高速缓存dns的搭建三、DNS相关名词解释四、权威DNS搭建编辑子配置文件&#xff08;主要写我们维护的域zone)开始解析 五、权威dns中的数据记录种类及应用编辑子配置文件&#xff08;主要写我们维护的域zone…

rman备份策略与RECLAIMABLE

在Oracle rman 需要keep 7days 时&#xff0c;report obsolete不能删除文件&#xff0c;但是如果Oracle已经备份到磁带上&#xff0c;RECLAIMABLE的空间Oracle内部可以自动释放的。 也就是说Oracle这是已经不能从磁盘回复&#xff0c;要磁带恢复复了 2023/12/24 10:35:31 …

js中的class类

目录 class构造函数方法原型方法访问器方法静态方法 继承super minxin关于多态 class 在ES6中之前如果我们想实现类只能通过原型链和构造函数的形式&#xff0c;不仅难以理解步骤也十分繁琐 在ES6中推出了class关键字&#xff0c;它可以在js中定一个类&#xff0c;通过new来实…

【极光系列】SpringBoot集成Mybatis

【极光系列】SpringBoot集成Mybatis 一.gitee地址 浅夏的猫 shawsongyue 直接下载可用 https://gitee.com/shawsongyue/aurora.git 二.mysql安装教程 详细参考我的另外一遍博客&#xff1a; https://blog.csdn.net/weixin_40736233/article/details/135582926?spm1001.201…

从物联网到数字孪生:智慧社区的未来之路

一、物联网在智慧社区中的应用与挑战 随着科技的飞速发展&#xff0c;物联网技术已经深入到我们生活的方方面面&#xff0c;尤其在智慧社区的建设中发挥着举足轻重的作用。物联网通过连接各种设备和系统&#xff0c;为社区居民提供了更便捷、高效的生活方式&#xff0c;同时也…

Hologres + Flink 流式湖仓建设

Hologres Flink 流式湖仓建设 1 Flink Hologres2 实时维表 Lookup 1 Flink Hologres holo在实时数仓领域非常受欢迎&#xff0c;一般搭配flinkhologres来做实时数仓&#xff0c;中间分层用holo&#xff0c;上下游一般依赖于holo的binlog来下发数据 2 实时维表 Lookup Holo…

微服务理解

分布式和微服务有什么区别 分布式是把一个集中式系统拆分成多个系统&#xff0c;每一个系统单独对外提供部分功能&#xff0c;整个分布式系统整体对外提供一整套服务。对于访问分布式系统的用户来说&#xff0c;感知上就像访问一台计算机一样. 而分布式架构的具体实现有很多种…

使用java内置工具jar手动创建xxx.jar文件

平时我们一般都是在IDE工具中使用插件打包JAVA项目为 XXX.jar文件, 其实这个工作我们手动也可以完成, 也非常简单, 使用JDK自带的jar命令行工具即可. 用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ... jar用法示例 创建 jar: …

第8章-第2节-Java中IO流的简单介绍

1、什么是流 我们可以先想象水流是怎样的&#xff1f;溪水不断流动&#xff0c;最终融入大海&#xff1b;我们今天的学习IO其实如同水流一样&#xff0c;当我们读取文件信息或者写入信息时&#xff0c;如同水流一样&#xff0c;不断读取或者写入&#xff0c;直到业务流程结束。…

高级分布式系统-第13讲 分布式控制经典理论

模糊控制器 模糊控制是以模糊集理论、模糊语言变量和模糊逻辑推理为基础的一种智能控制方法&#xff0c;它是从行为上模仿人的模糊推理和决策过程的一种智能控制方法。 该方法首先将操作人员或专家经验编成模糊规则&#xff0c;然后将来自传感器的实时信号模糊化&#xff0c;…

vue3-响应式基础之ref

声明响应式状态 ref() 在组合式 API 中&#xff0c;推荐使用 ref() 函数来声明响应式状态&#xff1a; ref() 接收参数&#xff0c;并将其包裹在一个带有 .value 属性的 ref 对象中返回&#xff1a; import { ref } from vue const count ref(0)console.log(count) // { va…

CAN工具 - ValueCAN3 - 基础介绍

关注菲益科公众号—>对话窗口发送 “CANoe ”或“INCA”&#xff0c;即可获得canoe入门到精通电子书和INCA软件安装包&#xff08;不带授权码&#xff09;下载地址。 CAN/CANFD通讯广泛存在于整个车载网络中&#xff0c;几乎每一块软硬件的开发都需要用到CAN工具&#xff0c…

Mask R-CNN网络中RPN区域建议网络的作用是什么?

问题描述&#xff1a;Mask R-CNN网络中RPN区域建议网络的作用是什么&#xff1f; 问题解答&#xff1a; 在 Mask R-CNN&#xff08;Mask Region-based Convolutional Neural Network&#xff09;中&#xff0c;RPN&#xff08;Region Proposal Network&#xff09;是用于生成…

机器学习 | 多层感知机MLP

机器学习 | 多层感知机MLP 1. 实验目的 自行构造一个多层感知机&#xff0c;完成对某种类型的样本数据的分类&#xff08;如图像、文本等&#xff09;&#xff0c;也可以对人工自行构造的二维平面超过3类数据点&#xff08;或者其它标准数据集&#xff09;进行分类。 2. 实验…

Hadoop 3.2.4 集群搭建详细图文教程

一、集群简介 Hadoop 集群包括两个集群&#xff1a;HDFS 集群、YARN 集群。两个集群逻辑上分离、通常物理上在一起&#xff1b;两个集群都是标准的主从架构集群。逻辑上分离 两个集群互相之间没有依赖、互不影响 物理上在一起 某些角色进程往往部署在同一台物理服务器上 MapR…

KY56 数制转换

进制转换板子 ti #include<bits/stdc.h>using namespace std;string ss "0123456789ABCDEF"; int a, b; string s;int main() {cin>>a>>s>>b;string str "";int len s.length();for(int i 0; i < len; ){int k 0;for(int…

Open3D (C++) 计算条件数

目录 一、算法原理1、条件数2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、条件数 条件数法是目前应用最为广泛的一种病态诊断方法。条件数的定义为: