vue 集成tinymce2实现图片,视频以及文件的上传

vue 集成tinymce2实现图片,视频以及文件的上传

1. 安装插件

(1)安装tinymce
npm install tinymce -S
(2)安装tinymce-vue
npm install @tinymce/tinymce-vue@3.0.1 -S
2. 复制静态文件到public目录
在这里插入图片描述
资源下载路径:https://download.csdn.net/download/weixin_44021888/88063970?spm=1001.2014.3001.5503
3. 新建组件:tinymce

<template>
    <div class="tinymce-box">
		<Editor v-model="contentValue" :init="init" :disabled="disabled" @onClick="onClick" :key="tinymceFlag"/>
	</div>
</template>

<script>
//引入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/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'  //文档属性
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'  //字数统计
import Cookies from 'js-cookie'

export default {
    name: 'TEditor',
    components: {
        Editor
    },
    props: {
        value: {
                type: String,
                default: ''
        },
        disabled: {
                type: Boolean,
                default: false
        },
        plugins: {
                type: [String, Array],
                default: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave '
        },
        toolbar: {
                type: [String, Array],
                default: 'fullscreen undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | image link media|\
                styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
                table image charmap hr pagebreak insertdatetime print preview | code selectall searchreplace visualblocks | indent2em lineheight formatpainter axupimgs'
        },
    },
    data(){
        return {
            tinymceFlag: 1,
            init: {
                media_url_resolver: function (data, resolve) {
                    console.log("data:", data)
                    console.log("resolve:", resolve)
                    try {
                        let videoUri = encodeURI(data.url);
                        let embedHtml = `<p>
                            <span
                                class="mce-object mce-object-video"
                                data-mce-selected="1"
                                data-mce-object="video"
                                data-mce-p-width="100%"
                                data-mce-p-height="auto"
                                data-mce-p-controls="controls"
                                data-mce-p-controlslist="nodownload"
                                data-mce-p-allowfullscreen="true"
                                data-mce-p-src=${videoUri} >
                                <video src=${data.url} width="100%" height="auto" controls="controls" controlslist="nodownload">
                                </video>
                            </span>
                        </p>
                        <p style="text-align: left;"></p>`;
                        resolve({ html: embedHtml });
                    } catch (e) {
                        resolve({ html: "" });
                    }
                },
                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: 'file edit',  //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”

                fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px',  //字体大小
                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;',  //字体样式
    //自带默认字体:'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,zapf dingbats'
                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插件时,此属性失效
                placeholder: '在这里输入文字',
                branding: false,  //tiny技术支持信息是否显示
                resize: false,  //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
                // statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示
                elementpath: false,  //元素路径是否显示

                // relative_urls: false,  //false: tinymce将不再自动将文件路径由绝对转为相对
                // convert_urls: false,  //false: tinymce将不再自动处理文件路径

                content_style: "img {max-width:100%;}",  //直接自定义可编辑区域的css样式
                // content_css: '/tinycontent.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
                paste_data_images: true,  //图片是否可粘贴
                images_upload_handler: (blobInfo, success, failure) => {
                    if(blobInfo.blob().size/1024/1024>3){
                        failure("上传失败,图片大小请控制在 3M 以内")
                    }else{
                        this.uploadFileData(blobInfo.blob(), success,)                     
                    }
                },
                // 用于上传文件
                file_picker_callback: function(callback, value, meta) {
                    let url = `${window.SITE_CONFIG['apiURL']}/resource/o_upload?token=${Cookies.get('token')}`
                     //文件
                    if(meta.filetype == 'media' || meta.filetype == 'file'){  
                        let input = document.createElement('input');//创建一个隐藏的input
                        input.setAttribute('type', 'file');
                        let that = this;
                        input.onchange = function(){
                            let file = this.files[0];//选取第一个文件
                            let chunkSize = 1024 * 1024 * 10; // 每个块的大小(字节),10M
                            let fileSize = file.size; // 文件的总大小
                            let totalChunks = Math.ceil(fileSize / chunkSize); // 文件被分成的总块数
                            let chunkNumber = 0; // 当前上传的块的编号
                            let startByte = 0; // 当前上传块的起始字节位置
                            let endByte = chunkSize; // 当前上传块的结束字节位置(不包括)
                            uploadChunk()
                            function uploadChunk() {
                                let chunk = file.slice(startByte, endByte); // 获取当前上传块的内容
                                let params = new FormData()
                                //params.append('file',blobInfo.blob())
                                params.append('file', chunk);
                                params.append("chunkNumber", chunkNumber);
                                params.append("totalChunks", totalChunks);
                                params.append("fileName", file.name);
                                const xhr = new XMLHttpRequest();
                                xhr.open("POST", url, true);
                                // 监听XMLHttpRequest对象的事件
                                xhr.onload = function() {
                                    if (xhr.status === 200) {
                                        // 上传成功,继续上传下一块
                                        chunkNumber++;
                                        startByte = endByte;
                                        endByte = Math.min(startByte + chunkSize, fileSize);
                                        if (startByte < fileSize) {
                                            uploadChunk();
                                        } else {
                                            // 所有块上传成功
                                            // 上传的图片
                                            callback(`${window.SITE_CONFIG['apiURL']}` +JSON.parse(xhr.response).data.resourceUrl , { title: file.name })
                                        }
                                    } else {
                                        // 上传失败,尝试重传当前块
                                        console.error(xhr.statusText);
                                        setTimeout(uploadChunk, 1000);
                                    }
                                };
                                xhr.onerror = function() {
                                    // 网络错误,尝试重传当前块
                                    console.error(xhr.statusText);
                                    setTimeout(uploadChunk, 1000);
                                };
                                // 发送POST请求
                                xhr.send(params);
                            }
                        }
                        //触发点击
                        input.click();
                    }
                },
            },
            contentValue: this.value
        }
    },
    watch: {
        value (newValue) {
            this.contentValue = newValue
        },
        contentValue (newValue) {
            this.$emit('input', newValue)
        },
    },
    activated() {
        // 每次都给编辑器改变不同的key值使其每次切换页面都重新加载,防止无限递增
        this.tinymceFlag=this.tinymceFlag===0?1 : 0 ;
    },
    mounted(){
        tinymce.init({})
        
    },
    methods: {
        // 添加相关的事件,可用的事件参照文档=> https://github.com/tinymce/tinymce-vue => All available events
        onClick(e){
            this.$emit('onClick', e, tinymce)
        },
        //清空内容
        clear(){
            this.contentValue = ''
        },
        uploadFileData(file, success) {
            let url = `${window.SITE_CONFIG['apiURL']}/resource/o_upload?token=${Cookies.get('token')}`
            let chunkSize = 1024 * 1024 * 10; // 每个块的大小(字节),10M
            let fileSize = file.size; // 文件的总大小
            let totalChunks = Math.ceil(fileSize / chunkSize); // 文件被分成的总块数
            let chunkNumber = 0; // 当前上传的块的编号
            let startByte = 0; // 当前上传块的起始字节位置
            let endByte = chunkSize; // 当前上传块的结束字节位置(不包括)
            uploadChunk()
            function uploadChunk() {
                let chunk = file.slice(startByte, endByte); // 获取当前上传块的内容
                let params = new FormData()
                //params.append('file',blobInfo.blob())
                params.append('file', chunk);
                params.append("chunkNumber", chunkNumber);
                params.append("totalChunks", totalChunks);
                params.append("fileName", file.name);
                const xhr = new XMLHttpRequest();
                xhr.open("POST", url, true);
                // 监听XMLHttpRequest对象的事件
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        // 上传成功,继续上传下一块
                        chunkNumber++;
                        startByte = endByte;
                        endByte = Math.min(startByte + chunkSize, fileSize);
                        if (startByte < fileSize) {
                            uploadChunk();
                        } else {
                            // 所有块上传成功
                            // 上传的图片
                            success(`${window.SITE_CONFIG['apiURL']}` +JSON.parse(xhr.response).data.resourceUrl)   
                        }
                    } else {
                        // 上传失败,尝试重传当前块
                        console.error(xhr.statusText);
                        setTimeout(uploadChunk, 1000);
                    }
                };
                xhr.onerror = function() {
                    // 网络错误,尝试重传当前块
                    console.error(xhr.statusText);
                    setTimeout(uploadChunk, 1000);
                };
                // 发送POST请求
                xhr.send(params);
            }
        }
    },
}
</script>

注意:如果上传过后的视频,只有一张图片的占位符,就把plugins和toolbar这两个属性里面的media去掉就可以了

plugins: {
	type: [String, Array],
	default: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave '
},
toolbar: {
	type: [String, Array],
	default: 'fullscreen undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | \
	 styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
	 table image charmap hr pagebreak insertdatetime print preview | code selectall searchreplace visualblocks | indent2em lineheight formatpainter axupimgs'
}

在这里插入图片描述

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

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

相关文章

数据分析的iloc和loc功能

大家好&#xff0c;在处理大型数据集时&#xff0c;使用有效的数据操作和提取技术是必要的。Pandas数据分析库提供了强大的工具&#xff0c;用于处理结构化数据&#xff0c;包括使用iloc和loc函数访问和修改DataFrame元素的能力。在本文中&#xff0c;我们将探讨iloc和loc之间的…

JAVA集成国密SM2

JAVA集成国密SM2加解密 一、pom配置二、代码集成2.1、目录结构2.2、源码2.3、测试 三、相关链接 国密算法概述&#xff1a;https://blog.csdn.net/qq_38254635/article/details/131801527 SM2椭圆曲线公钥密码算法 为非对称加密&#xff0c;基于ECC。该算法已公开。由于该算法…

rabbitMQ杂记

消息队列应用场景 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量 削锋等问题实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性&#xff1a; 解耦&#xff1a; 异步&#xff1a; 削峰&#xff1a; 常…

基于单片机的教室智能照明台灯控制系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;LCD1602液晶显示当前时间、年月日、时分秒、前教室人数&#xff1b;2路红外探头用来感应当前教室进出人数&#xff1b;按键可以设置当前时间、自动手动模式、开启和关闭教室灯光时间&#xff1b;在手动模式下&#xff0c;可以通过按…

Spring IoC及DI依赖注入

Spring 1.Spring的含义&#xff1a; Spring 可从狭义与广义两个角度看待 狭义的 Spring 是指 Spring 框架(Spring Fremework) 广义的 Spring 是指 Spring 生态体系 2.狭义的 Spring 框架 Spring 框架是企业开发复杂性的一站式解决方案 Spring 框架的核心是 IoC 容器和 AO…

透视表可视化简单案例

import pandas as pd import numpy as np import os basepath/Users/kangyongqing/Documents/kangyq/202307/标准版学期制C2/pathos.path.join(basepath,02freetime.csv) dtpd.read_csv(path,dtype{shifen:object}) print(dt.head()) import matplotlib.pyplot as pltfor i in …

Python探索金融数据进行时间序列分析和预测

大家好&#xff0c;时间序列分析是一种基于历史数据和趋势分析进行预测的统计技术。它在金融和经济领域非常普遍&#xff0c;因为它可以准确预测趋势并做出明智的决策。本文将使用Python来探索经济和金融数据&#xff0c;执行统计分析&#xff0c;并创建时间序列预测。 我们将…

55. 跳跃游戏

题目链接&#xff1a;力扣 解题思路&#xff1a; 贪心&#xff0c;因为题目只需要判断能够到达最后一个下标&#xff0c;所以可以从前往后遍历&#xff0c;使用maxEnd保存已经遍历过的位置能够跳跃达到的最大下标&#xff0c;如果maxEnd大于等于nums.length-1&#xff0c;则返回…

系统学习Linux-Rsync远程数据同步服务(三)

一、概述 rsync是linux 下一个远程数据同步工具 他可通过LAN/WAN快速同步多台主机间的文件和目录&#xff0c;并适当利用rsync 算法减少数据的传输 会对比两个文件的不同部分&#xff0c;传输差异部分&#xff0c;因此传输速度相当快 rsync可拷贝、显示目录属性&#xff0c…

ChatGPT:利用人工智能助推教育创新

当前&#xff0c;世界正需要一个更加开放的、更加个性化的学习空间&#xff0c;学生的个性发展和生存发展应该被关注和尊重&#xff0c;课程应该引导学生掌握有用的东西&#xff0c;学生之间的差距应该被正视&#xff0c;教育成功的标准也要被重新定义。过去&#xff0c;我们总…

N天爆肝数据库——MySQL(5)

本文主要对索引进行了讲解 这里写目录标题 本文主要对索引进行了讲解索引概述介绍优缺点索引结构二叉树红黑树B-Tree(多路平衡查找树)BTreeBTree与B-Tree区别: HashHash索引特点 为什么InnoDB存储引擎选择使用BTree索引结构&#xff1f;索引分类在InnoDB存储引擎中&#xff0c;…

基于微信小程序的求职招聘系统设计与实现(Java+spring boot+MySQL+微信小程序)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于微信小程序的求职招聘系统设计与实现&#xff08;Javaspring bootMySQL微信小程序&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java s…

(五)「消息队列」之 RabbitMQ 主题(使用 .NET 客户端)

0、引言 先决条件 本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口&#xff08;5672&#xff09;上运行。如果您使用了不同的主机、端口或凭证&#xff0c;则要求调整连接设置。 获取帮助 如果您在阅读本教程时遇到问题&#xff0c;可以通过邮件列表或者 RabbitMQ 社区…

【C++】list的使用及底层实现原理

本篇文章对list的使用进行了举例讲解。同时也对底层实现进行了讲解。底层的实现关键在于迭代器的实现。希望本篇文章会对你有所帮助。 文章目录 一、list的使用 1、1 list的介绍 1、2 list的使用 1、2、1 list的常规使用 1、2、2 list的sort讲解 二、list的底层实现 2、1 初构…

windows环境hadoop报错‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Hadoop版本为2.7.3&#xff0c;在环境配置好后&#xff0c;检查hadoop安装版本&#xff0c;报如标题所示错误&#xff0c;尝试网上主流的几种方法均无效。 错误&#xff1a;windows环境hadoop报错’D:\Program’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误方…

perl输出中文乱码【win10】

perl输出中文乱码 运行的时候输出的内容变成了中文乱码&#xff0c;原因首先来查找一下自己的perl的模块里面是否有Encode-CN。请运行打开你的cmd并输入perldoc -l Encode::CN 如果出现了地址 则就是有&#xff0c;如果没有需要进行该模块的安装。 安装方式有很多种&#xff0…

STM32F407-- DMA使用

目录 1. DMA结构体 STM32F103&#xff1a; STM32F407&#xff1a; 2. F4系列实现存储器到存储器数据传输 1&#xff09;结构体配置&初始化 2&#xff09;主函数 补充知识点&#xff1a;关于变量存储的位置&#xff0c;关于内部存储器一般存储什么内容 3. F4系列实现…

机器学习 day26(多标签分类,Adam算法,卷积层)

1. 多标签分类 多标签分类&#xff1a;对于单个输入特征&#xff0c;输出多个不同的标签y多类分类&#xff1a;对于单个输入特征&#xff0c;输出单个标签y&#xff0c;但y的可能结果有多个 2. 为多标签分类构建神经网络模型 我们可以构建三个不同的神经网络模型来分别预测…

C++第四讲

思维导图 仿照string类&#xff0c;实现myString类 /* ---------------------------------author&#xff1a;YoungZorncreated on 2023/7/19 19:20.--------------------------------- */ #include<iostream> #include<cstring>using namespace std;class myStri…

搜索引擎elasticsearch :安装elasticsearch (包含安装组件kibana、IK分词器、部署es集群)

文章目录 安装elasticsearch1.部署单点es1.1.创建网络1.2.加载镜像1.3.运行 2.部署kibana2.1.部署2.2.DevTools2.3 分词问题(中文不友好) 3.安装IK分词器3.1.在线安装ik插件&#xff08;较慢&#xff09;3.2.离线安装ik插件&#xff08;推荐&#xff09;1&#xff09;查看数据卷…