tinymce上传图片或者其他文件等等

news2025/2/25 12:15:59
  1. 技术选型

    tips: tinymce在vue中常用的有两种方式

    第一种: 官方组件,点我

    优点: 不用自己封装组件

    缺点: 需要申请特定apikey,类似于百度,高德地图;

    第二种: 就是下面这种

    优点: 不需要申请特定的apikey

    缺点: 需要自己手动的封装组件,灵活性高

    • Vue 2.x和3.x基本没有区别

    • tinymce version 6.8.3

      • 文档 中文 | 英文

      • 下载

        yarn add tinymce
        npm install tinymce

        cnpm install tinymce

        选择其中一种适合自己的就行

    • smms图床 点我申请

      • 文档 点我
  2. 如何使用

      1. 首先将node_modules中的tinymce包完整的复制到public并在node_modules中删除

      image-20240229135709288

      1. 在public/index.html中引入

        image-20240229135741985

      1. 为了方便我这边直接创建了一个vue文件,可以理解为vue组件,直接把源码放进去

        <template>
            <div class="chart-container">
                <el-row ref="tiny-editor" :id="`tiny-editor-${randomKey}`"></el-row>
        
                <el-row style="margin-top: 20px;">
                    <el-col :span="12" style="text-align: left;">
                        <el-button type="primary" @click="getEditorCtx">点击</el-button>
                    </el-col>
                </el-row>
            </div>
        </template>
        
        <script>
        import axios from "axios";
        const toolbar = [
            "template fullscreen undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link anchor alignleft aligncenter alignright alignjustify outdent indent bullist numlist blockquote subscript superscript removeformat ",
            "styleselect formatselect fontselect fontsizeselect table image axupimgs media emoticons charmap hr pagebreak insertdatetime selectall visualblocks searchreplace code print preview indent2em lineheight formatpainter",
        ];
        const plugins = "template preview searchreplace autolink directionality visualblocks visualchars " +
            "fullscreen image link media template code codesample table charmap pagebreak nonbreaking " +
            "anchor insertdatetime advlist lists wordcount autosave emoticons";
        
        import { Message } from "element-ui";
        
        export default {
            data() {
                return {
                    randomKey: Date.now(),
                };
            },
            mounted() {
                this.$nextTick(() => {
                    this.init()
                })
            },
        
            methods: {
                getEditorCtx() {
                    let str = tinymce.get(`tiny-editor-${this.randomKey}`).getContent();
                    console.log(str);
                },
        
                async uploadImageReq(formDataObj, config) {
                    const formData = new FormData();
                    Object.keys(formDataObj).forEach(key => {
                        formData.append(key, formDataObj[key])
                    })
                    try {
                        // 为了方便,我是在本地解决跨域问题
                        let res = await axios.post('/smms/upload', formData, {
                            onUploadProgress: e => {
                                config?.progress && config.progress(e.loaded / e.total * 100);
                            },
                            headers: {
                                // smms图床的token
                                // smms图床申请地址,放在了上面
                                Authorization: "XXXXXXXXX",
                                "Content-Type": "multipart/form-data"
                            }
                        });
                        return res;
                    } catch (error) {
                        Message.error(error);
                        return {}
                    }
                },
        
                uploadFile({ accept, fileType, errorHandle, uploadHandle }) {
                    const input = document.createElement('input');
                    // 是不是可支持的上传格式
                    const fileIsAdjective = (file) => {
                        let suffix = `.${file.type.toLowerCase().split('/')[1]}`;
                        return accept.includes(suffix);
                    }
        
                    input.setAttribute('type', 'file');
                    input.setAttribute('accept', accept);
        
                    input.onchange = (e) => {
                        let file = e.target.files[0];
                        if (!fileIsAdjective(file)) {
                            errorHandle(`请上传 ${accept}后缀的文件`)
                        } else {
                            uploadHandle({ file })
                        }
                    }
                    input.click();
                    input.remove()
                },
        
                getSupportedFileType(fileTypes) {
                    if (!fileTypes || fileTypes.length === 0) return "";
                    return fileTypes.map(item => item.toLowerCase()).toString();
                },
                async init() {
                    await tinymce.init({
                        selector: `#tiny-editor-${this.randomKey}`, //容器,可使用css选择器
                        language: 'zh_CN', //调用放在langs文件夹内的语言包
                        plugins,
                        toolbar,
                        menubar: false,
                        height: 800,
                        // 图片上传有两种方式,一种是只供上传的images_upload_handler
                        // 另一种就是file_picker_callback
                        // images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
                        //     this.uploadImageReq({
                        //         smfile: blobInfo.blob(),
                        //         format: 'json'
                        //     }, { progress })
                        //         .then(
                        //             res => {
                        //                 resolve(res?.data?.data?.url || "")
                        //             },
                        //             error => {
                        //                 reject(error)
                        //             }
                        //         )
                        // }),
        
                        // 我只写了一个图片上传,视频或者音频或者其他文件类似
                        file_picker_callback: (callback, value, meta) => {
                            const supportedImageTypes = ['.jpeg', '.jpg', '.png', '.gif', '.bmp', '.svg', '.webp'];
                            const supportedMediaTypes = ['.mp4', '.webm', '.ogg', '.flv', '.avi', '.wmv', '.mov', '.mkv'];
                            const supportedFileTypes = ['.pdf', '.doc', '.docx', '.txt', '.rtf', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.iso', '.dmg', '.apk'];
        
                            if (meta.filetype == 'image') {
                                this.uploadFile({
                                    accept: this.getSupportedFileType(supportedImageTypes),
                                    fileType: 'image',
                                    // 空处理函数
                                    errorHandle: (desc) => {
                                        callback('', { alt: desc });
                                    },
                                    // 上传处理函数
                                    uploadHandle: ({ file }) => {
                                        this.uploadImageReq({
                                            smfile: file,
                                            format: 'json'
                                        })
                                            .then(
                                                res => {
                                                    callback(res?.data?.data?.url || "", { alt: file.name })
                                                },
                                                error => {
                                                    callback("", { alt: error.toString() })
                                                }
                                            )
                                    }
                                })
                            }
                        }
                    });
                }
            },
        
            beforeDestroy() {
        
            }
        };
        </script>
        
        <style lang="scss" scoped>
        .el-carousel__item {
            background-color: #409eff;
        }
        
        .tox .tox-sidebar-wrap {
            &::-webkit-scrollbar {
                width: 0;
            }
        }
        </style>
        
      1. 预览,两种图片上传的方式有一些不同

        • 第一种

          image-20240229141911713

        • 第二种

          image-20240229141813484

tips:

需要注意的是tinymce不同版本的上传图片可能略微有些不同,请注意分辨

tinymce默认使用英文,如果需要中文化,需要去官网下载指定的zh_CN.js文件然后放到langs文件夹下面

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

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

相关文章

《Redis 设计与实现》读书概要

注&#xff1a; 《Redis 设计与实现》一书基于 Redis 2.9 版本编写&#xff0c;部分内容已过时&#xff0c;过时之处本文会有所说明。本文为读书笔记&#xff0c;部分简单和日常使用较少的知识点未记录。原书网页版地址 https://redisbook.com/ 一、底层数据结构 SDS(Simple Dy…

dcat admin 自定义页面

自定义用户详情页 整体分为两部分&#xff1a;用户信息、tab框 用户信息采用自定义页面加载&#xff0c;controller代码如下&#xff1a; protected function detail($id) {return Show::make($id, GameUser::with(finance), function (Show $show) {// 这段就是加载自定义页面…

Window部署Jaeger

参考&#xff1a;windows安装使用jaeger链路追踪_windows安装jaeger-CSDN博客 下载&#xff1a;Releases jaegertracing/jaeger GitHub Jaeger – Download Jaeger 目录 1、安装nssm 2、安装运行 elasticsearch 3、安装运行 3.1部署JaegerAgent 3.2部署JaegerCollec…

MySQL 存储过程批量插入总结

功能需求背景&#xff1a;今天接到产品经理核心业务表的数据压测功能&#xff0c;让我向核心业务表插入百万级的业务量数据&#xff0c;我首先想到的办法就是存储过程实现数据的批量 。 由于无法提供核心业务表&#xff0c;本文仅仅提供我刚刚自己创建的表bds_base_user 表做相…

7-AMCA NHS ester,113721-87-2,可以将荧光基团特异性地连接到目标分子上

113721-87-2&#xff0c;7-AMCA NHS ester&#xff0c;AMCA-OSu&#xff0c;AMCA-NHS&#xff0c;AMCA N-succinimidyl ester&#xff0c;7-AMCA NHS 活化酯&#xff0c;7-氨基-4-甲基香豆素-3-乙酸 N-琥珀酰亚胺酯&#xff0c;可以将荧光基团特异性地连接到目标分子上 您好&a…

IDC 中搭建 Serverless 应用平台:通过 ACK One 和 Knative 玩转云资源

作者&#xff1a;元毅、庄宇 如何打造云上&#xff08;公共云&#xff09;、云下&#xff08;IDC 数据中心&#xff09;统一的云原生 Serverless 应用平台&#xff0c;首先我们来看一下 ChatGPT 4 会给出什么样的答案&#xff1a; 如何打造云上、云下统一的云原生 Serverless…

echarts图表用key强制刷新后空白

我的需求是echarts图表全屏后退出全屏在edge浏览器上没有什么问题但是在Chrome浏览器上会出现表格的线不能变回原来的比例的问题 我就想在退出全屏的时候强制刷新一下echarts图表外面的这个div useEffect(() > {if (col) {col.addEventListener("webkitfullscreenchan…

Windows系统安装TortoiseSVN并结合内网穿透实现远程访问本地服务器——“cpolar内网穿透”

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

Node.js基础---npm与包

包 概念&#xff1a;Node.js 中的第三方模块又叫做包 来源&#xff1a;由第三方个人或团队开发出来的&#xff0c;免费使用&#xff0c;且为开源 为什么需要&#xff1a;Node.js的内置模块只有一些底层API&#xff0c;开发效率低 包是基于内置模块封装出来的&#xff0c;提供更…

express+mysql+vue,从零搭建一个商城管理系统6--数据校验和登录

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、修改models/user.js二、修改routes下的user.js三、Api新建user/login接口四、删除数据库原有数据&#xff0c;添加新验证规则的用户四、用户登录总结 前言 需求&#xff1a;主要学习express&#xff0c;…

IP源防攻击IPSG(IP Source Guard)

IP源防攻击IPSG&#xff08;IP Source Guard&#xff09;是一种基于二层接口的源IP地址过滤技术&#xff0c;它能够防止恶意主机伪造合法主机的IP地址来仿冒合法主机&#xff0c;还能确保非授权主机不能通过自己指定IP地址的方式来访问网络或攻击网络。 2.1 IPSG基本原理 绑定…

c# 广度优先搜索(Breadth-First Search,BFS)

在这篇文章中我将讨论用于树和图的两种遍历机制之一。将使用 C# 示例介绍广度优先搜索 (BFS)。图是最具挑战性和最复杂的数据结构之一。 广度优先搜索的工作原理&#xff1a;广度优先搜索 &#xff08;BFS&#xff09;是一种探索树或图的方法。在 BFS 中&#xff0c;您首先探索…

Mac 重新安装系统

Mac 重新安装系统 使用可引导安装器重新安装&#xff08;可用于安装非最新的 Mac OS&#xff0c;系统降级&#xff0c;需要清除所有数据&#xff09; 插入制作好的可引导安装器&#xff08;U盘或者移动固态硬盘&#xff09;&#xff0c;如何制作可引导安装器将 Mac 关机将 Ma…

【多智能体】MetaGPT配置教程(应用智谱AI的GLM-4)

MetaGPT配置教程&#xff08;使用智谱AI的GLM-4&#xff09; 文章目录 MetaGPT配置教程&#xff08;使用智谱AI的GLM-4&#xff09;零、为什么要学MetaGPT一、配置环境二、克隆代码仓库三、设置智谱AI配置四、 示例demo&#xff08;狼羊对决&#xff09;五、参考链接 零、为什么…

Appium手机Android自动化

目录 介绍 什么是APPium&#xff1f; APPium的特点 环境准备 adb(android调试桥)常用命令 appium图形化简单使用 连接手机模拟器 使用appium桌面端应用程序 ​编辑 整合java代码测试 环境准备 引入所需依赖 书写代码简单启动 ​编辑 Appium元素定位 id定位 介…

unity自定义着色器基础

这些内置渲染管线的着色器示例演示了编写自定义着色器的基础知识&#xff0c;并涵盖了常见的用例。 有关编写着色器的信息&#xff0c;请参阅编写着色器。 设置场景 第一步是创建一些用于测试着色器的对象。在主菜单中选择 Game Object > 3D Object > Capsule。然后&a…

AMEYA360:广和通5G智能模组SC171支持Android、Linux和Windows系统,拓宽智能物联网应用

世界移动通信大会2024期间&#xff0c;广和通宣布&#xff1a;5G智能模组SC171除支持Android操作系统外&#xff0c;还兼容Linux和Windows系统&#xff0c;帮助更多智能终端客户快速迭代产品&#xff0c;拓宽智能化应用覆盖范围。 广和通SC171系列基于高通QCM6490物联网解决方案…

2022年下半年教师资格证考试《综合素质》(中学)题

1.一位肖老师认为&#xff1a;“教师在教学中不能只关注学科层面的知识&#xff0c;还要爱学生&#xff0c;建立和谐的师生关系”。她在日常工作中以此为行动指南&#xff0c;这表明肖老师所处的教师专业发展阶段是&#xff08; B&#xff09;。 A“虚拟关注”阶段 B“自我更新…

ubuntu22.04工具整理以及安装使用方式

截图工具 火焰截图 安装&#xff1a; sudo apt install flameshot增加自定义快捷键&#xff1a; 然后就可是使用是指的快捷键进行截图了。 如果没有在截图上编辑的需要&#xff0c;其实自带的截图也够用的。

这可能是你少有的能get到测试用例编写精髓的机会!

自动化测试用例的编写是实现项目自动化的核心&#xff0c;合理的用例设计是保证自动化效益和实用性的关键&#xff0c;也直接决定了自动化脚本是否具备可扩展和可维护性。由此&#xff0c;本篇文章主要为大家介绍了测试用例编写的规范和注意事项。 一、自动化测试用例选择 自…