前端如何直接上传文件夹

前面写了一篇仿写el-upload组件,彻底搞懂文件上传,实现了选择/拖拽文件上传,我们经常看到一些网站支持直接选择整个文件夹上传,例如:宝塔面板、cloudflare托管、对象存储网站等等需要模拟文件路径存储文件的场景。那是怎么实现的呢?

依然从两方面来说:

  1. input选择文件夹
  2. 拖拽文件夹

input选择文件夹

在props.js中加一个属性,upload-folder是否支持上传文件夹

export default {// 前面的省略了...// 是否支持选择文件夹'upload-folder': {type: Boolean,default: false}
}

改一下input标签,依然是根据props的值动态判断是否支持上传文件夹。主要是webkitdirectory这个属性,由于不是一个标准属性,需要加浏览器前缀。

<input type="file" id="file" :multiple="multiple":accept="accept":webkitdirectory="uploadFolder":mozdirectory="uploadFolder":odirectory="uploadFolder"@change="handleChange"
>

注意:支持选择文件夹时就只能选择文件夹,无法选择文件。

那么如何获取选择的文件夹呢?其实我们最终要上传的依然是文件,也就是file对象,文件夹也是一个特殊的文件。

依然是通过inputonchange事件回调拿到上传的event

或者直接获取input这个dom对象,然后拿到files属性,结果是一样的。

// input选择文件回调
const handleChange = (event) => {console.log('[ files ] >', event.target.files)const inputDom = document.querySelector('#file')console.log('[ files ] >', inputDom.files)
}

可以看到,比选择单个文件时,多了一个webkitRelativePath属性,并且它是递归选择的文件夹,拿到这个文件夹及其子文件夹下所有的文件,我们可以通过这个属性拿到上传时文件所在的文件夹名称路径

拖拽文件夹

上篇文章讲过拖拽如何拿到文件,首先要准备一个用于拖拽放置的区域。
调用upload组件时,传入drag=true

<div class="drag-box" @dragover="handleDragOver"@dragleave="handleDragLeave"@drop="handleDrop"
>将文件拖到此处,或<span>点击上传</span>
</div>
// 拖放进入目标区域
const handleDragOver = (event) => {event.preventDefault()
}
// 拖拽放置
const handleDrop = (event) => {event.preventDefault()console.log('[ event ] >', event)
}

注意:和input上传不同,拖拽时,是可以同时拖拽文件和文件夹的。

因为可以同时拖拽文件和文件夹,我们就不能直接使用event.dataTransfer.files,如果刚好拖拽进来的是一个文件,那可以这么获取,如果是个文件夹呢?那就不行了。

同时拖拽一个文件和一个文件夹

这时候就要用到event.dataTransfer.items

// 拖拽放置
const handleDrop = (event) => {event.preventDefault()console.log(event.dataTransfer.items)
}

打印一下看看:

得到一个List类型的数据,里面是两个DataTransferItem,控制台无法直接查看它到底是个什么玩意儿。

看MDN,也看不出它具体是个啥。既然是List,遍历一下看看:

const handleDrop = (event) => {event.preventDefault()console.log(event.dataTransfer.items)for (const item of event.dataTransfer.items) {console.log('[ item ] >', item)}
}


可以看到不管是文件还是文件夹,都被识别成了file,只不过图片是直接能识别出type为image/png

查看MDN,https://developer.mozilla.org/zh-CN/docs/Web/API/DataTransferItem

点击查看itemPrototype,发现里面有个webkitGetAsEntry方法,执行它就能拿到item的具体信息。

看方法名,带了个webkit,但是这个方法除了Android Firefox浏览器以外都可以用。

for (const item of event.dataTransfer.items) {const entry = item.webkitGetAsEntry()console.log(entry)
}

依然拖动上面那个图片文件和一个文件夹:


可以看出,文件夹里面还有文件和文件夹,但是只显示了一个文件和一个文件夹,看来拖拽和input上传不一样,它不会自动的把里面所有的文件递归列出来。

通过isDirectory属性,就能区分是文件还是文件夹。除了这些基础属性以外,继续查看Prototype,可以看到还有一系列方法:

先看怎么拿到文件

entry是一个文件时,它有两个方法:createWriter()file(),查看MDN,https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry/createWriter

createWriter()已经废弃了,而且也不是我们今天要用的。

file()才是我们要找的。


这不就是我们熟悉的file对象吗,跟input上传拿到的一毛一样。

再看怎么拿到文件夹

查看MDN的Drop API webkitGetAsEntry()方法,https://developer.mozilla.org/zh-CN/docs/Web/API/DataTransferItem/webkitGetAsEntry可得,如果是文件夹,可以通过createReader方法创建一个文件目录阅读器,然后通过readEntries方法,重新拿到每个item,这就是event.dataTransfer.items里面的每个item

我们写一下试试

依然是之前那个图片和文件夹

只打印出了跟目录下一级的一个文件和一个文件夹,那下面还有一个文件怎么办呢?递归呀!

写一个递归读文件的方法。

const readFiles = async (item) => {if (item.isDirectory) {// 是一个文件夹console.log('=======文件夹=======');const directoryReader = item.createReader();// readEntries是一个异步方法const entries = await new Promise((resolve, reject) => {directoryReader.readEntries(resolve, reject);});let files = [];for (const entry of entries) {const resultFiles = await readFiles(entry);files = files.concat(resultFiles);}return files;} else {// 是一个文件console.log('=======文件=======');// file也是一个异步方法const file = await new Promise((resolve, reject) => {item.file(resolve, reject);});console.log('[ file ] >', file);return [file];}
}

handleDrop方法也要改一下

// 拖拽放置
const handleDrop = async (event) => {event.preventDefault()console.log(event.dataTransfer.items)const files = [];const promises = [];for (const item of event.dataTransfer.items) {const entry = item.webkitGetAsEntry();console.log('[ entry ] >', entry);promises.push(readFiles(entry));}const resultFilesArrays = await Promise.all(promises);const allFiles = resultFilesArrays.flat();console.log('[ All files ] >', allFiles);
}

再次拖拽上传看看

三个文件我们都拿到了。

总结

上传文件夹,还是直接使用input比较简单,使用它能直接拿到文件夹下所有的文件,以及每个文件在本地的路径,代码量也少很多。

拖拽的好处是文件和文件夹能一起上传。

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

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

相关文章

px4仿真实现无人机自主飞行

一,确定消息类型 无人机通过即在电脑是现自主飞行:思路如下。 通过Mavros功能包,将ROS消息转换为Mavlink消息。实现对无人机的控制。 几种消息之间的关系如下: 对于ROS数据,就是我们机载电脑执行ROS系统的数据。 对于Mavros消息,就是Mavros功能包内部的消息。查询网站…

leetcode:575. 分糖果(python3解法)

难度&#xff1a;简单 Alice 有 n 枚糖&#xff0c;其中第 i 枚糖的类型为 candyType[i] 。Alice 注意到她的体重正在增长&#xff0c;所以前去拜访了一位医生。 医生建议 Alice 要少摄入糖分&#xff0c;只吃掉她所有糖的 n / 2 即可&#xff08;n 是一个偶数&#xff09;。Al…

《数字图像处理-OpenCV/Python》连载(26)绘制椭圆和椭圆弧

《数字图像处理-OpenCV/Python》连载&#xff08;26&#xff09;绘制椭圆和椭圆弧 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第 4 章 绘图与鼠标交互 本章…

同心创变,共赢未来 ▏易我科技2023年度“春种秋收”经营分析会圆满举行

2023年10月12日—10月13日&#xff0c;易我科技举行了2023年度管理层秋季团建暨“春种秋收”经营分析会&#xff0c;全体管理干部参加了本次活动。 01 本次团建活动的主题是“同心创变&#xff0c;共赢未来”&#xff0c;旨在通过一系列有趣而富有挑战性的团队活动&#xff0c…

计算机能转嵌入式吗?

计算机能转嵌入式吗&#xff1f;计算机和嵌入式不是一个范畴的&#xff0c;嵌入式是计算机的一个求职方向或者细分领域。你应该把他和Java放在一个层次上而不是跟整个计算机放在一个层次上。最近很多小伙伴找我&#xff0c;说想要一些嵌入式资料&#xff0c;然后我根据自己从业…

Node编写用户注册接口

目录 前言 创建服务器 编写注册接口API 创建路由对象&#xff0c;将路由对象导出去 将路由对象导出到服务器中 判断用户发起注册请求时是否输入账号或密码 验证表单数据 在数据库中创建表 在node中绑定mysql数据库 判断用户注册的账号密码是否已经被注册 密码加密 完…

水质分析仪器升级新功能

水质分析仪器&#xff1a;是一种适用于水质多参数测试的便携式仪器。它具有7英寸的触摸彩色屏幕&#xff0c;用户可以通过触摸屏幕进行操作和查看测试结果。 该仪器主要用于测定COD&#xff0c;氨氮&#xff0c;总磷&#xff0c;总氮等常规水质指标&#xff0c;pH值、溶解氧、…

CVer从0入门NLP(一)———词向量与RNN模型

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

rancher2.6.4配置管理k8s,docker安装

docker快速安装rancher并管理当前k8s集群。 1、拉镜像 docker pull rancher/rancher:v2.6.4 2、启动rancher 启动很慢 --privileged必须拥有root权限&#xff0c;并挂载卷 docker run --privileged -d --restartunless-stopped -p 80:80 -p 443:443 -v /usr/local/docker_vo…

模拟经营微信小游戏-休闲餐厅上线了

《休闲餐厅》是一款关于餐厅经营的小游戏&#xff0c;玩家可以在游戏中扮演餐厅老板&#xff0c;经营自己的休闲餐厅&#xff0c;收集美丽的厨娘&#xff0c;炒菜、做饭、卖钱、装饰餐厅&#xff0c;享受经营的乐趣。 在游戏中&#xff0c;玩家可以解锁几百种菜品&#xff0c;每…

【JS的设计模式一】

本文参考书籍 《JavaScript设计模式与开发实践》 在 JavaScript 编程中&#xff0c;this 关键字总是让人感到迷惑&#xff0c;Function.prototype.call 和 Function.prototype.apply 这两个方法也有着广泛的运用。我们有必要在学习设计模式之前先理解 这几个概念。 this Java…

百度Comate代码助手全新上线SaaS服务,助力企业释放10倍软件生产力!

“1024”程序员节来临之际&#xff0c;百度智能云宣布百度Comate智能代码助手正式上线SaaS版本&#xff0c;可提供10余项编码功能&#xff0c;适配100种开发语言&#xff0c;面向广大企业和开发者提供更便捷、更灵活的智能编码工具&#xff0c;助力企业提升研发效率。即日起企业…

python控制Windows桌面程序自动化模块uiautomation

github仓库地址&#xff1a;GitHub - yinkaisheng/Python-UIAutomation-for-Windows: (Donot use 3.7.6,3.8.1):snake:Python 3 wrapper of Microsoft UIAutomation. Support UIAutomation for MFC, WindowsForm, WPF, Modern UI(Metro UI), Qt, IE, Firefox, Chrome ... uiaut…

领域驱动设计:基于DDD的微服务设计实例

文章目录 项目基本信息战略设计战术设计后续的工作 用一个项目来了解 DDD 的战略设计和战术设计&#xff0c;走一遍从领域建模到微服务设计的全过程&#xff0c;一起掌握 DDD 的主要设计流程和关键 点。 项目基本信息 项目的目标是实现在线请假和考勤管理。功能描述如下&…

新材料制造业工厂MES系统解决方案

新材料是指具有优异性能和功能的材料&#xff0c;是国家战略性新兴产业的重要支撑。新材料涵盖了高性能结构材料、先进功能材料、生物医用材料、智能制造材料等多个领域&#xff0c;广泛应用于航空航天、电子信息、节能环保、生物医药等行业&#xff0c;对于提升国家综合实力和…

生成式AI革命对亚马逊的电商业务是威胁还是机遇?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;当所有人都在关注生成式AI是如何威胁谷歌(GOOG)的搜索业务之际&#xff0c;投资界却忽视了一个事实&#xff0c;即&#xff1a;它也给亚马逊(AMZN)的电商业务带来了威胁。 &…

使用Selenium-PO设计模式提高Web自动化测试效率

PO&#xff08;page object&#xff09;设计模式是在自动化中已经流行起来的一种易于维护和减少代码的设计模式。在自动化测试中&#xff0c;PO对象作为一个与页面交互的接口。测试中需要与页面的UI进行交互时&#xff0c;便调用PO的方法。这样做的好处是&#xff0c;如果页面的…

哪吒X选车指南:推荐哪吒X 500lite 版

当下,紧凑型纯电动SUV市场新车不断,可选项越来越多。最近哪吒汽车又上市一款“大气舒适新标杆”——哪吒X,限时权益价10.88万元-12.88万元,以大空间,超舒适,更安全等优势,强势对标AION Y Plus和元Plus等车型。 很多有购车打算的消费者看过价格和配置,直呼哪吒X是“性价比显眼包…

使用Vscode创建一个C_Hello程序

Vscode用来学习C语言语法确实很方便。问题是安装好了&#xff0c;不会用&#xff0c;或编译失败&#xff0c;也是常有的事情&#xff0c;其中一个原因就是不会创建工作区。下面介绍使用Vscode创建一个C语言工作区。有时候看着很简单&#xff0c;时间久了&#xff0c;我竟然忘记…

Mr.Alright---MTK安卓13 抬手亮屏功能的逻辑

该功能在系统设置-显示-拿起设备时唤醒 alps\vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\display\LiftToWakePreferenceController.javapublic boolean isAvailable() {SensorManager sensors (SensorManager) mContext.getSystemServ…