前端文件上传组件最全封装+删除+下载+预览

前言:使用的是若依的框架+element ui+vue2封装的。如果有不对的地方欢迎指出。后台管理使用,文件需要上传。回显列表,详情也需要回显+预览

// 开始封装组件:封装在 src/components/FileUpload/index.vue中
<template><div class="upload-file"><el-uploadmultiplename="multipartFile":action="uploadFileUrl":data="{ 上传时附带的额外参数 }":limit="limit":file-list="fileList":before-upload="handleBeforeUpload":on-exceed="handleExceed":on-error="handleUploadError":on-success="handleUploadSuccess":show-file-list="false":headers="headers"class="upload-file-uploader"ref="fileUpload"><!-- 上传按钮 --><el-button size="mini" type="primary" plain v-if="!disabled">选取文件</el-button><!-- 上传提示 --><div class="el-upload__tip" slot="tip" v-if="showTip && !disabled">请上传<template v-if="fileSize">大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template><template v-if="fileType">格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>的文件</div></el-upload><!-- 文件列表,我们功能需要 删除文件、下载文件、预览文件功能 --><transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul" style="min-width: 300px"><li class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList" :key="file.fileId"><el-link class="link" :href="`${baseUrl}${file.filePath}`" :underline="false" target="_blank"><span class="el-icon-document" style="padidng-left: 10px">{{ getFileName(file.fileName) }}</span></el-link><div class="controls"><div class="ele-upload-list__item-content-action" style="width: 50px; text-align: center"><el-link :underline="false" @click="handleDelete(index)" type="danger" v-if="!disabled">删除</el-link></div><div class="ele-upload-list__item-content-action" style="width: 50px; text-align: center"><el-link :underline="false" @click="handlePreview(file)" type="danger">预览</el-link></div><div class="ele-upload-list__item-content-action" style="width: 50px; text-align: center"><el-link :underline="false" @click="handleDownload(file)" type="danger">下载</el-link></div></div></li></transition-group><!-- 文件预览功能,点击文件列表后的预览按钮,需要预览文档,pdf,excel,照片,视频,音频。其他没有封装,所以就不支持 --><el-dialog title="文件预览" :visible.sync="preview.open" append-to-body :before-close="previewCancel"><vue-office-docx v-if="fileSuffix == 'docx'" :src="preview.url" style="height: 100vh" /><vue-office-excel v-else-if="fileSuffix == 'xlsx'" :src="preview.url" style="width: auto; height: 100vh" /><vue-office-pdf v-else-if="fileSuffix == 'pdf'" :src="preview.url" style="height: 100vh" /><div style="text-align: center" v-else-if="fileSuffix == 'img'"><el-image style="width: 500px" :src="preview.url" fit="fill" :preview-src-list="[preview.url]"></el-image></div><div style="text-align: center" v-else-if="fileSuffix == 'mp3'"><audio controls loop ref="myAudio" autoplay class="my-audio"><source :src="preview.url" /></audio></div><div style="text-align: center" v-else-if="fileSuffix == 'mp4'"><video-app :src="preview.url" :second="1"></video-app></div><div style="text-align: center" v-else>暂不支持该文件预览,请下载预览</div></el-dialog></div>
</template><script>
import { getToken } from "@/utils/auth";
import { 查看和下载的接口,后端给的 } from "";//引入VueOfficeDocx组件,需要npm安装
import VueOfficeDocx from "@vue-office/docx";
import "@vue-office/docx/lib/index.css";//引入VueOfficeExcel组件,需要npm安装
import VueOfficeExcel from "@vue-office/excel";
import "@vue-office/excel/lib/index.css";//引入VueOfficePdf组件,需要npm安装
import VueOfficePdf from "@vue-office/pdf";import VideoApp from "./video.vue"; // 这个是我封装的视频预览的组件export default {name: "FileUpload",props: {// 数量限制limit: {type: Number,default: 5,},// 大小限制(MB)fileSize: {type: Number,default: 20,},// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: {type: Array,default: () => ["docx", "pptx", "pdf"],},// 是否显示提示isShowTip: {type: Boolean,default: true,},formFileList: {type: Array,default: () => [],},disabled: {type: Boolean,default: false,},// 培训记录附件的类型busiType: {type: String,},},components: {VueOfficeDocx,VueOfficeExcel,VueOfficePdf,VideoApp,},data() {return {number: 0,uploadList: [],baseUrl: // 地址 ,uploadFileUrl: , // 上传文件服务器地址headers: {Authorization: "Bearer " + getToken(),},fileList: [],lookFile: false,url: "",// 文件预览preview: {open: false,url: "",},fileSuffix: "",};},watch: {// 编辑和详情的回显fileListformFileList: {handler(val) {if (val !== undefined) {this.fileList = val;}if (val == null) {this.fileList = [];return;}},deep: true,immediate: true,},},computed: {// 是否显示提示showTip() {return this.isShowTip && (this.fileType || this.fileSize);},},methods: {// 上传前校检格式和大小handleBeforeUpload(file) {// 校检文件类型if (this.fileType) {const fileName = file.name.split(".");const fileExt = fileName[fileName.length - 1];const isTypeOk = this.fileType.length ? this.fileType.indexOf(fileExt) >= 0 : [];if (!isTypeOk) {this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);return false;}}// 校检文件大小if (this.fileSize) {const isLt = file.size / 1024 / 1024 < this.fileSize;if (!isLt) {this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);return false;}}this.$modal.loading("正在上传文件,请稍候...");this.number++;return true;},// 文件个数超出handleExceed() {this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);},// 上传失败handleUploadError(err) {this.number--;this.$modal.msgError("上传文件失败,请重试");this.$modal.closeLoading();},// 上传成功回调handleUploadSuccess(res, file) {if (res.code === 200) {this.uploadList.push(res.data);this.$modal.closeLoading();this.uploadedSuccessfully();} else {this.number--;this.$modal.closeLoading();this.$modal.msgError(res.msg);this.$refs.fileUpload.handleRemove(file);this.uploadedSuccessfully();}},// 删除文件handleDelete(index) {this.fileList.splice(index, 1);this.$emit("input", this.listToString(this.fileList));},// 上传结束处理uploadedSuccessfully() {if (this.number > 0 && this.uploadList.length === this.number) {this.fileList = this.fileList.concat(this.uploadList);this.uploadList = [];this.number = 0;this.$emit("input", this.listToString(this.fileList));this.$modal.closeLoading();this.$emit("fileUploadSuccess", this.fileList);}},// 获取文件名称getFileName(name) {if (name?.lastIndex/Of("/") > -1) {return name.slice(name.lastIndexOf("/") + 1);} else {return name;}},// 对象转成指定字符串分隔listToString(list, separator) {let strs = "";separator = separator || ",";for (let i in list) {strs += list[i].url + separator;}return strs != "" ? strs.substr(0, strs.length - 1) : "";},resetFileList() {this.fileList = [];},// 下载handleDownload(file) {downloadFile(file.fileId).then((res) => {this.exportFunction(res, file.fileName, file.fileType);});},exportFunction(response, name, type) {const link = document.createElement("a");const blob = new Blob([response], { type });link.style.display = "none";link.href = URL.createObjectURL(blob);link.setAttribute("download", name, type);document.body.appendChild(link);link.click();document.body.removeChild(link);},// 预览handlePreview(file) {this.preview.url = "";if (file.fileType.indexOf("image") !== -1) {this.fileSuffix = "img";} else {this.fileSuffix = file.suffix;}showFileURL(file.fileId).then((res) => {this.preview.url = defaultSettings.minioUrl + res;if (file.suffix == "mp3") {this.$nextTick((res) => {this.$refs.myAudio.load();this.$refs.myAudio.play();});}this.preview.open = true;});},previewCancel() {this.preview.open = false;this.preview.url = "";if (this.fileSuffix == "mp3") {this.$refs.myAudio.pause();}},},
};
</script><style scoped lang="scss">
::v-deep .el-button--primary.is-plain {color: var(--select-selected-color);background: var(--table-content-bColor);border-color: var(--search-back);
}
::v-deep .el-button--primary.is-plain:hover,
::v-deep .el-button--primary.is-plain:focus {border-color: var(--select-selected-color);background-color: var(--select-selected-color);color: #fff !important;
}.upload-file-uploader {margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {border: 1px solid #e4e7ed;line-height: 2;margin-bottom: 10px;position: relative;
}
.upload-file-list .ele-upload-list__item-content {display: flex;color: inherit;.link {flex: 1;display: block;margin-left: 2px;::v-deep .el-icon-document {width: 310px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}}.controls {display: flex;}
}
.ele-upload-list__item-content-action .el-link {margin-right: 10px;
}
::v-deep {.x-spreadsheet-table {width: auto !important;}
}
.my-audio {width: 100%;
}
</style>

video组件封装:


<template><div class="m-video" :class="{'u-video-hover': !hidden}" :style="`width: ${width}px; height: ${height}px;`"><videoref="veo":style="`object-fit: ${zoom};`":src="src":poster="veoPoster":width="width":height="height":autoplay="autoplay":controls="!originPlay&&controls":loop="loop":muted="autoplay || muted":preload="preload"crossorigin="anonymous"@loadeddata="poster ? () => false : getPoster()"@pause="showPlay ? onPause() : () => false"@playing="showPlay ? onPlaying() : () => false"@click.prevent.once="onPlay"v-bind="$attrs">您的浏览器不支持video标签。</video><svg v-show="originPlay || showPlay" class="u-play" :class="{'hidden': hidden}" :style="`width: ${playWidth}px; height: ${playWidth}px;`" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4.75 6.75C4.75 5.64543 5.64543 4.75 6.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25 6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H6.75C5.64543 19.25 4.75 18.3546 4.75 17.25V6.75Z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15.25 12L9.75 8.75V15.25L15.25 12Z"></path></svg></div>
</template>
<script>
export default {name: 'Video',props: {src: { // 视频文件url,必传,支持网络地址 https 和相对地址 require('@/assets/files/Bao.mp4')type: String,required: true,default: ''},poster: { // 视频封面url,支持网络地址 https 和相对地址 require('@/assets/images/Bao.jpg')type: String,default: ''},second: { // 在未设置封面时,自动截取视频第 second 秒对应帧作为视频封面type: Number,default: 0.5},width: { // 视频播放器宽度type: Number,default: 800},height: { // 视频播放器高度type: Number,default: 450},autoplay: { // 视频就绪后是否马上播放type: Boolean,default: false},controls: { // 是否向用户显示控件,比如进度条,全屏type: Boolean,default: true},loop: { // 视频播放完成后,是否循环播放type: Boolean,default: false},muted: { // 是否静音type: Boolean,default: false},preload: { // 是否在页面加载后载入视频,如果设置了autoplay属性,则preload将被忽略;type: String,default: 'auto' // auto:一旦页面加载,则开始加载视频; metadata:当页面加载后仅加载视频的元数据 none:页面加载后不应加载视频},showPlay: { // 播放暂停时是否显示播放器中间的暂停图标type: Boolean,default: true},playWidth: { // 中间播放暂停按钮的边长type: Number,default: 96},zoom: { // video的poster默认图片和视频内容缩放规则type: String,default: 'contain' // none:(默认)保存原有内容,不进行缩放; fill:不保持原有比例,内容拉伸填充整个内容容器; contain:保存原有比例,内容以包含方式缩放; cover:保存原有比例,内容以覆盖方式缩放}},data () {return {veoPoster: this.poster,originPlay: true,hidden: false}},mounted () {if (this.autoplay) {this.hidden = truethis.originPlay = false}/*自定义设置播放速度,经测试:在vue2中需设置:this.$refs.veo.playbackRate = 2在vue3中需设置:veo.value.defaultPlaybackRate = 2*/// this.$refs.veo.playbackRate = 2},methods: {/*loadeddata 事件在媒体当前播放位置的视频帧(通常是第一帧)加载完成后触发preload为none时不会触发*/getPoster () { // 在未设置封面时,自动获取视频0.5s对应帧作为视频封面// 由于不少视频第一帧为黑屏,故设置视频开始播放时间为0.5s,即取该时刻帧作为封面图this.$refs.veo.currentTime = this.second// 创建canvas元素const canvas = document.createElement('canvas')const ctx = canvas.getContext('2d')// canvas画图canvas.width = this.$refs.veo.videoWidthcanvas.height = this.$refs.veo.videoHeightctx.drawImage(this.$refs.veo, 0, 0, canvas.width, canvas.height)// 把canvas转成base64编码格式this.veoPoster = canvas.toDataURL('image/png')},onPlay () {if (this.originPlay) {this.$refs.veo.currentTime = 0this.originPlay = false}if (this.autoplay) {this.$refs.veo.pause()} else {this.hidden = truethis.$refs.veo.play()}},onPause () {this.hidden = false},onPlaying () {this.hidden = true}}
}
</script>
<style lang="scss" scoped>
* {box-sizing: border-box;margin: 0;padding: 0;
}
.m-video {display: inline-block;position: relative;background: #000;cursor: pointer;.u-play {position: absolute;top: 0;right: 0;bottom: 0;left: 0;margin: auto;fill: none;color: #FFF;pointer-events: none;opacity: 0.7;transition: opacity .3s;path {stroke: #FFF;}}.hidden {opacity: 0;}
}
.u-video-hover {&:hover {.u-play {opacity: 0.9;}}
}
</style>

使用组件:

import FileUpload= from "@/components/FileUpload=";
<el-form-item label="文件上传"><file-uploadref="fileResetRef"@fileUploadSuccess="fileUploadSuccessHandle":formFileList="form.files" // 回显的数据文件列表:disabled="isReadonly" // 区分编辑还是查看:file-type="[ // 支持的类型'png','jpg','docx','xlsx','pptx','pdf','mp3','mp4','zip',]"></file-upload>
</el-form-item>
// 文件上传成功的展示
fileUploadSuccessHandle1(fileList) {this.form.files = fileList;
},

上传组件效果图:
在这里插入图片描述
上传的文件列表:
在这里插入图片描述

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

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

相关文章

js文件上传 分片上传/断点续传/极速秒传

(极速秒传)利用md5判断上传的文件是否存在 MD5信息摘要算法&#xff0c;一种被广泛使用的密码散列函数&#xff0c;可以产生出一个128位&#xff08;16字节&#xff09;的散列值&#xff08;hash value&#xff09;&#xff0c;用于确保信息传输完整一致。 每一个文件都会生成…

每日一题——LeetCode1005.K次取反后最大化的数组和

方法一 个人方法&#xff1a; 将数组从小到大排序后&#xff0c;假设数组共有n个负数&#xff0c;要使数组的和尽可能大就要尽可能将较大的负数变为正数&#xff0c;有以下几种情况&#xff1a; 1、k<n&#xff0c;那就把数组前k个负数都转为正数即可。 2、k>n&#xf…

TemporalKit的纯手动安装

最近在用本地SD安装temporalkit插件 本地安装插件最常见的问题就是&#xff0c;GitCommandError:… 原因就是&#xff0c;没有科学上网&#xff0c;而且即使搭了ladder&#xff0c;在SD的“从网址上安装”或是“插件安装”都不行&#xff0c;都不行&#xff01;&#xff01;&am…

红酒送礼选对不选贵,这些挑选技巧一定要收藏好

遇到过节的时候&#xff0c;大家都张罗着买点什么东西送给亲朋好友老丈人&#xff0c;领导同事丈母娘。云仓酒庄的品牌雷盛红酒LEESON分享选择最多的就是烟酒茶&#xff0c;烟和茶已经成为常态&#xff0c;送红酒却是一种新风尚。在琳琅满目的红酒品类中&#xff0c;怎么才能选…

谷歌推出了一种名为提示扩展(Prompt Expansion)的创新框架,旨在帮助用户更轻松地创造出既高质量又多样化的图像。

谷歌推出了一种名为提示扩展&#xff08;Prompt Expansion&#xff09;的创新框架&#xff0c;旨在帮助用户更轻松地创造出既高质量又多样化的图像。 论文标题: Prompt Expansion for Adaptive Text-to-Image Generation 论文链接: https://arxiv.org/pdf/2312.16720.pdf 问…

我们一起聊聊MySQL 索引的底层逻辑

数据结构以及算法 索引的本质其实就是一种数据结构。我们都希望查询数据的速度能尽可能的快&#xff0c;因此数据库系统的设计者会从查询算法的角度进行优化。最基本的查询算法当然是顺序查找&#xff0c;这种复杂度为 O(n) 的算法在数据量很大时显然是糟糕的&#xff0c;好在…

Uibot (RPA设计软件)培训前期准备指南————课前材料

紧接着小北的上一篇博客&#xff0c;友友们我们即将开展新课的学习~RPA 培训前期准备指南——安装Uibot(RPA设计软件&#xff09;-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/135348488?spm1001.2014.3001.5502 课程安排如下&#xff1a; 序号 日期 内容 视…

linux下超级程序!在linux界面实现类图像化界面的操作体验!

linux下超级程序&#xff01;在linux界面实现类图像化界面的操作体验&#xff01; 本期带来一个超级程序&#xff01;在linux界面实现类图像化界面的操作体验。具体功能代码如下: 1500行完整代码想要完成部署&#xff0c;只需在本地创建一个LinuxGJ.sh的文件&#xff0c;然后…

JavaScript可选链接

注&#xff1a;本节仍然使用之前的饭店的对象&#xff0c;可以看上几篇文章查看代码 ● 如果我们想要看看饭店周一的开门时间&#xff0c;我们会这么写 console.log(restaurant.openingHours.mon.open);原因是我们在开放时间中并没有定义周一的开放时间&#xff0c;所有会报错…

Leetcod面试经典150题刷题记录 —— 链表篇

Leetcod面试经典150题刷题记录-系列Leetcod面试经典150题刷题记录——数组 / 字符串篇Leetcod面试经典150题刷题记录 —— 双指针篇Leetcod面试经典150题刷题记录 —— 矩阵篇Leetcod面试经典150题刷题记录 —— 滑动窗口篇Leetcod面试经典150题刷题记录 —— 哈希表篇Leetcod面…

使用Python做个可视化的“剪刀石头布”小游戏

目录 一、引言 二、环境准备与基础知识 三、游戏界面制作 四、游戏逻辑实现 五、代码示例 六、游戏测试与优化 七、扩展与改进 八、总结 一、引言 “剪刀石头布”是一种古老的手势游戏&#xff0c;它简单易懂&#xff0c;趣味性强&#xff0c;适合各个年龄段的人参与。…

Java基础-----Date类(二)

文章目录 1. LocalDate:获取本地日期2. 单独获取日期时间类中的每个值3. 使用给定值修改日期4. 设置日期和时间的偏移量5. Instant类6. DateTimeFormatter格式化和解析6.1 将LocalDate转换成字符串String格式6.2 将时间戳转换成字符串String格式6.3 将字符串解析成日期6.4 将字…