[封装自己的ui组件库] upload的实现与难点

news2025/2/5 14:49:56

效果

1、服务文件(tmp为保存上传文件文件夹)

2、点击上传

3、图片列表

4、拖拽

5、手动上传

5、上传失败

6、服务

问题

1、如何打开文件列表

2、如何取出文件

3、对取出的文件校验?

4、如何发送请求(多文件上传?)

5、如何完成上传列表展示

6、拖拽上传?

7、可扩展?

思路

在实现的过程中大致思考了一下流程

1 点击或取文件(input:file)

2 获取文件进行校验(大小和类型)

3 创建初始化列表(对上传文件进行包装)

4 根据是否自动上传决定是否直接添加上传列表,还是手动上传至上传列表

5 监视初始化列表,取出上传列表数据,使用formdata转换为二进制数据通过ajax发送至后台

6 请求过程中监视请求结果动态展示列表

7 多文件使用原生的multipart可实现

8 拖拽可使用drop,dragover,dragenter,dragleave,dragover的事件

。。。。

实现

1、利用input:file获取文件

<input ref="inputFile" type="file" name="" id="" @change="selectfilesChange" :multiple="multiple">

 // 点击触发弹窗的事件pushUploadFrame() {// 清空inputFilethis.$refs.inputFile.value = nullthis.$refs.inputFile.click();}, 

2、取出文件+文件校验

 // 文件选中变化selectfilesChange(e, files) {if (e) {// 转换为真实数组以便使用数组的方法this.selectFileList = Array.from(e.target.files);} else {this.selectFileList = Array.from(files);console.log(files);}// 判断文件是否已上传// 前去校验let { isResult, content } = this.handlerFileAccept(this.selectFileList);if (isResult) {// 文件校验成功事件this.$emit('acceptAfter', this.selectFileList)// 添加到初始化上传列表this.addUpList(this.selectFileList)} else {// 触发文件上传失败事件this.$emit('uploadError', content)}},// 处理文件校验相关handlerFileAccept(accEptList) {// console.log(accEptList);// 没有文件时不做处理if (!accEptList.length) return;let { size, accept } = this;// 类型校验分割为数组let accepts = accept.split(',')// 校验处理let sizeResult = accEptList.every(child => child.size <= size);// 类型校验let typeResult = accEptList.every(child => {if (/\/\*$/.test(accepts)) {return true} else {return accepts.includes(child.type)}})if (sizeResult && typeResult) {return { isResult: true, content: '文件校验成功' }} else if (!typeResult) {return { isResult: false, content: `文件类型不符合要求, 需要${accept}类型文件` }} else if (!sizeResult) {return { isResult: false, content: `文件大小不得超过${size / 1024}kb` }}}, 

3、对初始化列表的数据进行包装

 // 添加到上传列表addUpList(files) {// 生成符合上传要求的文件let uploadList = files.map((child, index) => {// console.log(child);// 生成传输请求格式return {header: this.headers, //请求头部withCredentials: this.withCredentials, // 是否允许cooikeuid: Date.now() + index,// status: 0, // 上传状态 // 0:就绪, 1: 上传中, -1 :上传失败,2:上传成功file: child, // 文件size: child.size, // 文件大小name: child.name, // 文件名称type: child.type, // 文件类型onProgress: (e, uid) => {// 监视上传进度// console.log('上传中', e);this.$emit('uploadProgress', e, child)this.$children.filter(item => item.$el.className == 'fileList')[0].uploadPropress(e, uid)},onError: (err, uid) => {// 上传失败触发的事件// console.log('上传失败', err, child);this.$emit('uploadError', err)this.$children.filter(item => item.$el.className == 'fileList')[0].uploadError(uid)},onSuccess: (res, uid) => {// 上传成功后触发的事件// console.log('上传成功', res, child);this.$emit('uploadSuccess', res, child)this.$children.filter(item => item.$el.className == 'fileList')[0].uploadSuccess(uid)}}})if (this.autoUpload) {// 添加到生成的上传文件列表中uploadList.forEach(item => {this.initFileList.push(item)});} else {uploadList.forEach(item => {this.uploadFileList.unshift(item)})}// 清空添加的文件列表this.clearFileList()}, 

4 监视初始化列表,一旦有数据将其添加入上传列表

initFileList: {handler(newV) {// console.log('待上传', newV);if (newV.length && this.autoUpload) {// console.log('触发上传');// 取出第一个文件let startFile = this.initFileList.shift()// 触发上传方法this.upload(startFile)} else {console.log('初始化列表没有待上传的文件了');}}, immediate: true} 

5、创建请求并发送

 // 上传方法upload(file) {if (this.autoUpload) {// 添加到上传列表this.uploadFileList.unshift(file)}//创建 xhrconst xhr = new XMLHttpRequest();// 配置请求方法和路径xhr.open('POST', this.action)// 上传成功xhr.addEventListener('load', () => {if (xhr.status < 200 || xhr.status >= 300) {return file.onError('未知错误', file.uid);}// 触发上传成功file.onSuccess(xhr.response, file.uid);})// 上传失败xhr.addEventListener('error', (e) => {file.onError(e, file.uid)})// 监视上传进度if (xhr.upload) {xhr.upload.onprogress = function progress(e) {if (e.total > 0) {e.percent = e.loaded / e.total * 100;}file.onProgress(e, file.uid);};}// 转换为二进制文件let fd = new FormData()fd.append(file.name, file.file)// 携带的额外参数if (this.data) {for (const key in this.data) {if (Object.hasOwnProperty.call(this.data, key)) {fd.append(key, this.data[key])}}}// 上传的文件xhr.send(fd)}, 

6、动态展示列表

<template><div class='fileList' :style="{ 'max-width': maxWidth + 'px' }"><!-- 文件列表 --><template v-if="!preView"><div class="fileDetail" v-for="item in uploadList" :key="item.uid" :data-uid="item.uid"><!-- 左侧文件图标 --><span class="leftIcon"><tyIcon type="file"></tyIcon></span><!-- 文件名称 --><p class="detail" :title="item.name" v-text="item.name"></p><!-- 右侧成功/删除图标 --><span class="rightIcon"><tyIcon type="close" @click.native="handlerDeteleFile(item.uid)"></tyIcon><tyIcon type="success" v-if="item.isSuccess" style="color:#94d82d;"></tyIcon><tyIcon type="warring" v-if="item.isError" style="color:#ffa94d;"></tyIcon></span></div></template><template v-else><div class="preView" v-for="item in uploadList" :key="item.uid" :data-uid="item.uid"><!-- 左侧文件图标 --><div class="view"><img class="img" :src='item.base64' /></div><!-- 文件名称 --><p class="detail" :title="item.name" v-text="item.name"></p><!-- 右侧成功/删除图标 --><span class="rightIcon"><tyIcon type="close" @click.native="handlerDeteleFile(item.uid)"></tyIcon><tyIcon type="success" v-if="item.isSuccess" style="color:#94d82d;"></tyIcon><tyIcon type="warring" v-if="item.isError" style="color:#ffa94d;"></tyIcon></span></div></template></div>
</template>

<script> import tyIcon from '../../icon/src/main.vue'
export default {name: 'fileList',props: {files: {type: Array,default: () => []},// 最大宽度maxWidth: {type: [Number]},// 删除文件事件deleteFile: {type: Function},preView: {type: Boolean,default: false}},data() {return {uploadList: []}},methods: {// 点击删除图标触发handlerDeteleFile(uid) {// 触发对应的删除方法this.$emit('deleteFile', uid)},// 触发更改进度uploadPropress(e, uid) {console.log(e, uid);},// 上传成功uploadSuccess(uid) {this.uploadList = this.uploadList.map(child => {if (child.uid == uid) {child.isSuccess = true}return child})},// 上传失败uploadError(uid) {this.uploadList = this.uploadList.map(child => {if (child.uid == uid) {child.isError = true}return child})// 删除上传的文件},},watch: {files: {handler(newV) {if (this.preView) {this.uploadList = newV.map(child => {if (child.file) {let reader = new FileReader();reader.readAsDataURL(child.file); //将文件读取为 DataURL,也就是base64编码reader.onload = function (ev) { //文件读取成功完成时触发var dataURL = ev.target.result; //获得文件读取成功后的DataURL,也就是base64编码child.base64 = dataURL}}return child})}this.uploadList = newV.map(child => {if (!child.isSuccess) {child.isSuccess = false;}if (!child.isError) {child.isError = false;}return child})}}},components: {tyIcon}
} </script>

<style lang='less' scoped> @import '../../../css/upload.less'; </style> 

7、拖拽

 // 设置拖拽setDarg() {let uploadRef = this.$refs.uploadRef// 在元素内结束拖拽触发uploadRef.addEventListener('drop', (e) => {e.stopPropagation()e.preventDefault()// console.log('drop', e.dataTransfer.files);// 触发文件上传this.selectfilesChange(undefined, e.dataTransfer.files)// 触发事件this.$emit('handlerDrop', e.dataTransfer.files)}, false)// 拖拽离开元素时触发uploadRef.addEventListener('dragleave', (e) => {e.stopPropagation()e.preventDefault()this.$emit('dropLeave')})// 拖拽进入元素时触发uploadRef.addEventListener('dragenter', (e) => {e.stopPropagation()e.preventDefault()this.$emit('dropEnter')})// 拖拽在元素内时持续触发uploadRef.addEventListener('dragover', (e) => {e.stopPropagation()e.preventDefault()this.$emit('dropChange')})}, 

8 可提供的扩展

 props: {// 限制上传文件的大小size: {type: [Number],default: 500 * 1024},// 限制上传文件类型accept: {type: String,default: 'image/*'},// 是否允许多文件上传multiple: {type: Boolean,default: false},// 上传成功方法uploadSuccess: {type: Function},// 上传失败事件uploadError: {type: Function},// 文件校验通过后触发acceptAfter: {type: Function},// 移除文件时触发fileRemove: {type: Function},// 上传的请求头headers: {type: Object,default: () => { }},// 是否自动上传文件autoUpload: {type: Boolean,default: true},// 上传的服务器地址action: {type: String,default: '#'},// 是否允许cooikewithCredentials: {type: Boolean,default: false,},// 开启预览图preView: {type: Boolean,default: false},// 携带的参数data: {},// 上传时触发的钩子uploadProgress: {type: Function},// 是否展示上传列表showList: {type: Boolean,default: true},// 开启拖动上传drag: {type: Boolean,default: false},// 拖拽文件进入是触发dropEnter: {type: Function},// 拖拽文件离开时触发dropLeave: {type: Function},// 拖拽进入时持续触发dropChange: {type: Function},// 拖拽在指定文件中触发handlerDrop:{type: Function}...} 

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

基于遗传算法改进的DELM预测 - 附代码

遗传算法改进的深度极限学习机DELM的回归预测 文章目录遗传算法改进的深度极限学习机DELM的回归预测1.ELM原理2.深度极限学习机&#xff08;DELM&#xff09;原理3.遗传算法4.遗传算法改进DELM5.实验结果6.参考文献7.Matlab代码1.ELM原理 ELM基础原理请参考&#xff1a;https:…

three.js之由线到管(管道缓冲几何体)

文章目录简介例子解释专栏目录请点击 简介 一条曲线怎么生成一个个曲线路径一行的管状呢&#xff1f;这个时候我们就用到了three.js的一个api:TubeGeometry&#xff0c;官网 例子 <!DOCTYPE html> <html lang"en"><head><meta charset"…

python连接OB绑定变量问题

某现场客户程序使用python&#xff0c;引用了jaydebeapi库连接oceanbase的jdbc驱动oceanbase-client-*.*.*.jar JayDeBeApi是一个python模块&#xff0c;可通过它来使用java的JDBC连接数据库&#xff0c;为该数据库提供了 Python DB-API v2.0 OB官网给的jaydebeapi连接ob的列子…

Hadoop2.x源码64位编译

编译必须环境&#xff1a;hadoop源码【使用的是2.10.2版本】、JDK8、maven、ant 、protobuf【版本必须是2.5.0&#xff0c;否则编译会报错org.apache.maven.plugin.MojoExecutionException: protoc version is libprotoc 3.21.12, expected version is 2.5.0】 安装 glibc-hea…

【剧前爆米花--爪哇岛寻宝】Comparator,Comparable接口以及toString和equals方法的重写应用

作者&#xff1a;困了电视剧 专栏&#xff1a;《JavaSE语法与底层详解》 文章分布&#xff1a;这是一篇关于接口的文章&#xff0c;在本篇文章中我会将接口常用的一些实例进行讲解&#xff0c;以及部分方法在重写中的思想。 目录 Comparable和Comparator接口使用 Object类 t…

敏捷的发展史(二)

2010年之前&#xff0c;大多数敏捷管理的例子都是在软件开发团队中&#xff0c;几乎没有看到大型组织实施敏捷。 2015年&#xff0c;开始有一些非常大的组织成功地在组织的大部分区域内采用敏捷管理的讨论。 为了验证&#xff0c;史蒂夫丹宁邀请那些拥抱敏捷的公司聚在一起分享…

天天说手撕AVL树?你真的能撕下来吗?(详细解释+代码注释)

目录 前言 一、什么是AVL树&#xff1f; 二、模拟实现AVL树 2.1、定义AVL树 2.2、插入结点功能 2.2.1、先把值为val的结点插入到AVL树中 2.2.2、根据平衡因子来对树进行调整 2.3、AVL树的旋转 2.3.1、右单旋 2.3.2、左单旋 2.3.3、左右双旋 2.3.4、右左双旋 2.3、验证AVL树…

zabbix监控Gbase8a

部署​参考文章 部署zabbix [rootgba02 ~]# cat /etc/redhat-release CentOS Linux release 8.5.2111 [rootgba02 ~]# uname -a Linux gba02 4.18.0-348.el8.x86_64 #1 SMP Tue Oct 19 15:14:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux 安装nginx [rootgba02 ~]# systemctl…

漏洞扫描原理及X-Scan安装

漏洞扫描原理及X-Scan使用 漏洞扫描原理 1.概念&#xff1a; 漏洞扫描技术是建立在端口扫描技术的基础之上的&#xff0c;从对黑客的攻击行为的分析和收集的漏洞来看&#xff0c;绝大多数都是针对某一个特定的端口的&#xff0c;所以漏洞扫描技术以与端口扫描技术同样的思路来开…

外汇天眼:流动性风险加剧!欧洲天然气价格上限180欧,WTI原油回升

欧盟天然气价格上限协议达成、美欧原油期货持仓降至2015年以来的最低水平&#xff1b;能源价格流动性风险进一步加剧&#xff0c;WTI原油继续“寻底”。 每兆瓦时180欧元&#xff01;欧盟天然气价格上限协议达成 周一&#xff08;12月19日&#xff09;经历两个月谈判后&#x…

图解NumPy,这是理解数组最形象的一份教程了

本文用可视化的方式介绍了 NumPy 的功能和使用示例。NumPy 软件包是 Python 生态系统中数据分析、机器学习和科学计算的主力军。它极大地简化了向量和矩阵的操作处理。Python 的一些主要软件包&#xff08;如 scikit-learn、SciPy、pandas 和 tensorflow&#xff09;都以 NumPy…

MySQL使用MyCat实现分库分表

MySQL分库分表的实现方式有&#xff1a; shardingJDBC&#xff1a;基于AOP原理&#xff0c;在应用程序中对本地执行的SQL进行拦截&#xff0c;解析、改写、路由处理。需要自行编码配置实现&#xff0c;只支持java语言&#xff0c;性能较高。MyCat&#xff1a;数据库分库分表中…

我国盆栽行业发展向好 服务、信息、性价比高度结合的销售模式势在必行

盆栽系由中国传统的园林艺术变化而来&#xff0c;其定义是指栽在盆里的活体植物的总称。盆栽是温室花卉生产的主要方式之一&#xff0c;即便于控制各种生活条件&#xff0c;有利于花卉的促控栽培&#xff0c;还便于搬移&#xff0c;即可陈设于室内&#xff0c;又可布景于庭院。…

Metal每日分享,基于色温调整白平衡滤镜效果

本案例的目的是理解如何用Metal实现基于色温调整白平衡效果滤镜&#xff0c;主要就是消除或减轻日光下偏蓝和白炽灯下偏黄&#xff0c;简单讲把应该是白色的调成白色或接近白色&#xff0c;不使其严重偏色&#xff1b; Demo HarbethDemo地址iDay每日分享文档地址 实操代码 /…

如何多人配音?告诉你这几个实用的配音技巧

大家平常在刷短视频时&#xff0c;有没有刷到过一些搞笑配音视频呢&#xff1f;有些视频是由多人互动或者一人扮演多角而成的&#xff0c;这些创作者把当下比较热门的话题通过配音的方式呈现出来&#xff0c;或让我们捧腹大笑、或让我们引起思考。如果你也想通过这种方式来制作…

JVS低代码基础介绍

企业信息化底座 JVS是面向软件开发团队可以快速实现应用的基础开发脚手架&#xff0c;主要定位于企业信息化通用底座&#xff0c;采用微服务分布式框架&#xff0c;提供丰富的基础功能&#xff0c;集成众多业务引擎&#xff0c;它灵活性强&#xff0c;界面化配置对开发者友好&a…

Git仓库创建、代码更新、代码提交完整版(Gitee、Github、GitLab对比)

区别 Gitee、Github、GitLab三个都提供了 个人和团队存储、分享、发布和协同开发项目的中心化云存储功能 名称代码版块控制管理工具是否收费搭建环境联网/github git 公有仓库免费 私有仓库收费&#xff08;鼓励代码共享&#xff09; 企业私有需要搭建可离线&#xff08;分布…

在英特尔独立显卡上部署YOLOv5 v7.0版实时实例分割模型

作者&#xff1a;贾志刚 英特尔物联网创新大使  目录 1.1 YOLOv5实时实例分割模型简介 1.2 英特尔消费级锐炫™ A 系列显卡简介 1.3 在英特尔独立显卡上部署YOLOv5-seg模型的完整流程 1.3.1 搭建YOLOv5开发环境和OpenVINO部署环境 1.3.2 验证YOLOv5开发环境和OpenVINO部…

Spring Cloud之acos服务注册与Dubbo

Spring Cloud之acos服务注册与Dubbo nacos是springcloud的扩展&#xff0c;注册中心功能通过NacosDiscoveryClient 继承DiscoveryClient&#xff0c;在springcloud中&#xff0c;与Eureka可以无侵入的切换。注册中心可以手动剔除服务实例&#xff0c;通过消息通知客户端更新缓…

【推荐】数据湖技术及实践与案例资料汇总合集47篇

数据湖或hub的概念最初是由大数据厂商提出的&#xff0c;表面上看&#xff0c;数据都是承载在基于可向外扩展的HDFS廉价存储硬件之上的。但数据量越大&#xff0c;越需要各种不同种类的存储。最终&#xff0c;所有的企业数据都可以被认为是大数据&#xff0c;但并不是所有的企业…