web前端文件上传可选择的4种方式

2023-11-05

在web前端开发中,文件上传属于很常见的功能,不论是图片、还是文档等等资源,或多或少会有上传的需求。一般都是从添加文件开始,然后读取文件信息,再通过一定的方式将文件上传到服务器上,以供后续展示或下载使用。
本文将讲述文件上传中所能用到的4种添加读取文件的方式:

  • input上传控件
  • 拖拽文件
  • 粘贴文件
  • File System Access API

input上传控件

首先介绍的,就是最常用的html表单控件:input[type=file],它允许用户打开系统的文件选择框,选择相应文件后加载并读取到相关文件信息,它支持单个文件或多个文件,多文件选择增加属性:multiple
input上传控件的浏览器支持度最高,作为html的基础标签功能,一直都是web开发中使用最多的一种文件上传方式。
它支持的主要属性:

  • multiple:允许用户选择多个文件进行添加
  • accept:指定文件上传时能接受的文件类型(MIME),如 image/pngimage/*video/* 等等

html控件代码如下,接受批量添加图片文件:

<input id="fileInput" type="file" accept="image/*" multiple onchange="selectFile()" />

以上代码添加了 onchange 事件,当选中不同文件时,可以获取到文件信息:

const fileInput = document.getElementById('fileInput')
function selectFile () {
  const file = fileInput.files[0]
}

上面的js代码,就是监听事件的函数,通过元素对象,读取正在添加的文件信息。
或者也可以添加事件监听器,同样能读取到文件信息:

document.getElementById('fileInput').addEventListener('change', (e) => {
  const file = e.target.files[0]
}, false)

这里读取的上传控件元素对象的文件属性 files,它是 FileList 对象,一个针对 File 对象的集合。

文件信息是使用 File 对象API,用于接收文件,具体的介绍可见博文 详解前端二进制:Blob、File、FileReader、ArrayBuffer、TypeArray、DataView

修改上传控件样式

input文件上传控件,之前被诟病比较多的就是样式太单一,在整体设计风格上会有很多局限,但我们可以使用css样式中的一个伪元素来美化该控件。
这个伪元素就是 ::file-selector-button,通过它可以对上传控件按钮进行颜色字体背景边框等进行各种样式设置。具体信息可见博文CSS伪元素详解以及伪元素与伪类的区别

input::file-selector-button {
  border: 1px solid #f00;
  font-size: 20px;
  border-radius: 5px;
  background-color: azure;
}

以上代码,即通过伪元素对上传控件按钮进行了样式的修改,效果如下图。
在这里插入图片描述
当然,这个伪元素只能修改按钮的样式,至于上传控件的其他部分包括文字内容,无法修改,仍然会较影响设计,这时候我们就需要使用另外的方式,比如隐藏上传控件。

隐藏上传控件

我们只需要让上传控件隐藏不显示,但在点击的时候还能够触发上传控件的文件选择框,就能达到自定义各种好看样式的上传控件的目的。
隐藏上传控件的方式有很多种,下面介绍其中一种,通过透明度的方式,先设置一个外部div元素,div内添加input上传元素,并设置透明度为0,达到不显示的目的,代码如下:

<div class="input-container">
  点击 <span style="color: red;">选择文件</span> 进行上传
  <input class="input-file" type="file" name="file" multiple="multiple" />
</div>
.input-container {
  position: relative;
  width: 250px;
  margin: 20px 0;
}
.input-file {
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  opacity: 0;
}

以上代码,input上传控件元素通过绝对定位的方式置于div上层,透明度为0隐藏,视觉上只会显示底层div的内容(我们可自定义样式),但input控件会优先响应点击事件,这样就可以达到添加文件的目的。
当然,类似隐藏的方法还有多种,基于css样式实现,可以设计出更多更好看的文件上传组件。

拖拽文件

第二种介绍的添加文件的方式是拖拽文件,就是通过拖放(drag and drop)过程中的事件监听读取文件。主要针对的是三个拖拽相关的事件:

  • dragenter:拖拽进入当前节点时触发
  • dragover:拖拽位于节点上方时,持续触发
  • drop:当拖拽至目标节点,释放时触发

我们只需要在页面上添加一个div元素标签,设置一定的区域大小,对这个元素的拖放事件进行监听即可:

const dropArea = document.getElementById('dropArea')
const stopPropagation = (e) => {
  e.stopPropagation()
  e.preventDefault()
}

dropArea.addEventListener('dragenter', stopPropagation, false)
dropArea.addEventListener('dragover', stopPropagation, false)
dropArea.addEventListener('drop', (dragEvent) => {
  stopPropagation(dragEvent)
  const file = dragEvent.dataTransfer.files[0]
}, false)

以上代码,监听了拖放事件,当我们从电脑上拖动一个文件到指定div区域内,释放以后,就能获取了drop事件对象 DragEvent,它拥有一个独有属性 dataTransfer,是一个 DataTransfer 对象,能读取到文件属性 ‘files’。
接下来,我们了解下 DataTransfer 对象。

Datatransfer

Datatransfer 对象用于获取拖放事件中传输的数据。所有的拖放事件都包含一个该类型的属性。
我们在事件监听中读取到该对象后,可以从它的属性里读取到需要的数据,如文件信息。
该对象除了从拖放事件中获取以外,还能从 ClipboardEvent.clipboardData 剪切板事件上获取(后文会介绍)。

Datatransfer 对象拥有的属性和方法:

  • dropEffect:获取当前选定的拖放操作类型或者设置的为一个新的类型。值必须为none, copy, link或move。
  • effectAllowed:提供所有可用的操作类型。必须是none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized 之一。
  • files:包含数据传输中可用的所有本地文件的列表。
  • items:只读,提供一个包含所有拖动数据列表的DataTransferItemList对象。
  • types:只读,一个提供dragstart事件中设置的格式的字符串数组。
  • clearData():删除与给定类型关联的数据。不给定参数则删除所有
  • getData():检索给定类型的数据。
  • setData():设置给定类型的数据。不存在则添加到末尾,存在则替换相同位置的数据。
  • setDragImage():用于设置自定义的拖动图像。

粘贴文件

除了拖拽文件以外,还有依赖剪切板的粘贴文件的方式,通过复制文件,并在指定元素区域内粘贴文件,这个时候,我们监听元素的 onpaste 事件,就可以得到想要的文件了。

onpaste事件:在将剪切板内容粘贴到文档时触发的事件,事件对象 ClipboardEvent,拥有一个 clipboardData 只读属性,存放剪切板的数据,它是一个DataTransfer对象(见上文)。
有了这个事件和相应的属性,实现文件读取就比较方便了:

document.getElementById('textarea').onpaste = (clipboardEvent) => {
  clipboardEvent.stopPropagation()
  clipboardEvent.stopImmediatePropagation()
  
  const { items, files } = clipboardEvent.clipboardData

  if (files && files.length) {
    const file = files[0]
  }
}

以上代码,通过监听一个 textarea 元素的 onpaste 事件,读取到 clipboardData 属性,包含了 files,就读取到了文件信息,使用上也较为方便。

粘贴的方式,除了文件以外,文本内容之类的数据也可以处理。

File System Access API

File System Access API 文件系统访问API,允许访问读写文件及管理功能。它拥有多个API对象和方法,能够从用户的本地设备上进行文件交互,核心功能包括读写文件、访问目录结构等等。它的浏览器支持正在慢慢变好,chrome、edge与opera都已支持,然而firefox还不支持。
下文将着重介绍文件读取的API对象和方法,让我们能了解这种新的文件读取的方式。

showOpenFilePicker

showOpenFilePicker 是用于打开文件选择框,选中并添加文件的一个异步方法,支持 async/await
它的语法:showOpenFilePicker(options)

options 可选属性对象:

  • multiple:布尔值,是否能选择多个文件。默认false,表示只能选择一个文件。
  • excludeAcceptAllOption:布尔值,是否排除types对象中所有的accept文件类型。默认false,不排除。
  • types:可选的文件类型数组,数组元素也是对象,支持以下参数:
    • description:表示文件或者文件夹的描述。
    • accept:接受的文件类型,对象,用法如 { 'image/*': ['.png', '.gif', '.jpeg', '.jpg'] }

showOpenFilePicker 方法返回一个 FileSystemFileHandle 对象数组,用来处理文件信息。

FileSystemHandle 对象提供一个系统文件的句柄,用于读取文件对象。它提供了一个方法:getFile(),返回文件对象,支持 async/await
下面看一个具体的示例:

<button id="openImageFile">打开图片</button>
document.getElementById('openImageFile').addEventListener('click', async () => {
  const handle = await showOpenFilePicker({
    multiple: true,
    types: [{
      description: '图片',
      accept: { 'image/png': ['.jpg', '.png'] }
    }]
  })

  if (handle && handle.length) {
    const handleFile = handle[0]
    const file = await handleFile.getFile()
  }
}, false)

以上代码,通过按钮的click事件,使用showOpenFilePicker方法打开选择文件框,添加一个文件。

上传

读取到文件信息以后,就是将文件上传到服务器上,可以使用基本的上传方式,HTML表单:

<form action="url" enctype="multipart/form-data" method="post">
  <input name="fileInput" type="file" />
  <button type="submit">提交</button>
</form>

以上代码,就是通过form表单,以 post 的方式将文件上传到 action 属性对应的url上传链接。
这种方式一般针对的就是input文件上传控件。

除了HTML表单的方式以外,我们还是可以使用 FormData 对象,构造一个表单数据,通过ajax等方式进行异步数据上传:

const formData = new FormData()
formData.append('file', file, file.name)

const xhr = new XMLHttpRequest()
xhr.open('POST', 'url', true)
xhr.send(formData)

以上代码,就是通过构造一个 formData 实例,添加文件数据,通过 xhr 的方式提交到对应的url上传链接。
构造 FormData 对象的方式,适用于以上4种文件读取方式,只要获取到文件信息,就可以通过这种方式上传到服务器。

总结

本文总结了前端web当前能够添加读取文件的4种方式,如果我们需要开发一个比较完善的图片上传组件,那么可能需要点击、拖拽、粘贴多种功能,这就需要使用到前三种文件读取方式。文件系统访问API鉴于兼容性还有待提升,我们可以作为后备的方案使用。
有了文件读取的方式,那我们要完成上传功能,就可以使用 HTML表单 提交,或者 FormData 对象上传了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

web前端文件上传可选择的4种方式 的相关文章

  • 当条件满足时如何打破CasperJS的重复功能?

    我想知道是否可以打破 casper repeat 循环 我有这个脚本可以做到这一点 在谷歌上搜索特工001 特工002 特工003 特工004 特工005 特工006 直到特工011 我希望它在找到文本 詹姆斯 邦德 后停止循环 现在它找到
  • 单击上一页的按钮路由到该页面后如何刷新页面

    我有 2 个页面 一个主页和一个页面 2 当我单击主页上的按钮时 它会路由到 page2 现在 单击主页上的按钮后 当我到达第 2 页时 它应该刷新 因为我的项目中存在一些缓存问题 我在ngoninit上添加了window location
  • 错误找不到“pages”目录。请在项目根目录下创建一个”

    以前我的项目设置是 public next src pages components assets next config js 这工作正常 但我将结构更改为以下 public src client next config js jscon
  • 具有两组子组件的 React 组件

    我正在创建一个组件 需要接收两组子组件并放置在组件的两个不同部分中 let CreditCardForm icons fields gt div div div div icons div div div fields div let Cr
  • Angular.js:未捕获的错误,没有模块:myapp

    我也在尝试引导 angular js 项目 这是我的index html div p Loading p div
  • React 不响应按键事件

    我正在尝试实现一些非常基本的按键检测 但我根本无法让它工作 我有一个裸露的组件 应该在onKeyDown事件 但控制台中没有任何内容被注销 class App extends React Component constructor prop
  • JavaScript 中的正则表达式用于验证十进制数字

    我想要 JavaScript 中的正则表达式来验证十进制数字 它最多只允许两位小数 例如 它应该允许10 89但不是10 899 它还应该只允许一个句点 例如 它应该允许10 89但不是10 8 9 尝试使用以下表达式 d d 0 2 如果
  • less.js - 在解析器回调中获取变量值

    我正在使用 less js 1 3 0 在客户端将 less 解析为 css 在解析器的回调中 我想获取每个变量的值 我尝试了以下方法但没有成功 var data colour red example background color co
  • 如何获取传单标记簇中点击事件的图块?

    这是我的代码 function onMapClick e e originalEvent defaultPrevented true var orig e originalEvent console log orig target map
  • 通过 Javascript 将图像切割成碎片

    我正在创建一个简单的拼图游戏 为了做到这一点 我需要将我正在使用的图片切成 20 块 Javascript 有没有办法将一张图片切成 20 个相等的部分 并将它们保存为网页中的 20 个不同的对象 或者我只需要进入 Photoshop 自己
  • JSON对象的长度[重复]

    这个问题在这里已经有答案了 该函数生成一个包含 json 对象的数组 var estoque function unpack estoque tnm total estoque vl id tid st tnm tnm split tota
  • 使用 jquery 通配符检查 cookie 名称

    我有一个生成动态 cookie 的表单 例如 webform 62 1234356 62 1234356 可以是任意数字 我需要使用一些通配符检查来检查名称以 webform 开头的 cookie 是否存在 下面不起作用 if cookie
  • Javascript 正则表达式来匹配正则表达式

    我正在研究一个特殊的正则表达式来匹配 javascript 正则表达式 现在我有这个正则表达式工作 i g m 例如 foo match i g m gt foo foo undefined foo i match i g m gt foo
  • 如果多个键是相同的 JS,则对对象中的值求和

    例如我有 5 个对象 row aa col 1 value 1 row bb col 2 value 1 row bb col 3 value 1 row aa col 1 value 1 row aa col 2 value 1 我想对值
  • Javascript 中的线性回归 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在网络浏览器中用 Javascript 进行最小二乘拟合 目前 用户使用 HTML 文本输入输入数
  • 通过多个回调优雅地传递“点击事件”

    当未登录的用户单击给定的按钮时 我想停止该事件 收集他的 oauth 收集他的电子邮件 如果我没有 然后执行该事件 我想用 javascript 来做所有事情 因为这会让事情变得更加简单 这就是我执行它的方式 我有两个问题 有没有更优雅的方
  • 如何查看网站浏览者的操作系统?

    我运行的是 Ubuntu 8 04 最近在访问网站时收到以下错误 请使用运行 Windows 98 2000 Me NT 或 XP 的计算机返回 www site com 网站如何知道我正在运行哪个操作系统 是仅通过 javascript
  • 如何按字母顺序排序并先小写排序

    如何获得以下排序的结果Food to Eat然后是 食物123 显然 第二个较低的 o 应该将 要吃的食物 带到排序后的第一个项目中 我很惊讶这个问题不容易通过谷歌找到答案 这个壮举没有包含在 javascript 标准中也让我感到惊讶 F
  • 将 div 文本分配给变量然后显示它

    我有一个简单的任务 我试图完成学习 JavaScript 但一直无法找到明确的答案 这是代码 div Testing div 基本上我希望将方框 div 中的文本存储到变量中 然后 我想在页面的不同部分显示该变量的文本 使用上面的代码我得到
  • WooCommerce 使用 AJAX 设置购物车数量?

    我已经为此绞尽脑汁好几天了 需要一些指导 我正在为 WooCommerce 网站完全从头开始制作自定义主题 现在我正在尝试让购物车功能正常工作 我一直试图使用按钮 来更新购物车中产品的数量 对我来说问题似乎是WC 我在functions p

随机推荐

  • Protege新手入门(基础篇)

    通过制作一个简单的动物本体 来使大家了解protege建立owl的基础用法 步骤1 建立新的项目 打开protege 然后会出现对话框 点击Create New Project 出现Create New Project对话框后 选择OWL
  • 【kali】kali换了root权限后无法打开firefox浏览器

    从普通权限换成root权限后发现火狐进不去鸟 终端报错 Running firefox as root in a regular user s sessin is not supported HOME is home miehahaha w
  • redis(1)-hiredis-Windows下的编译

    1 linux编译说明文档 GitHub sewenew redis plus plus Redis client written in C 2 hiredis 编译 2 1 hiredis下载 https github com redis
  • hdu 1060

    Given a positive integer N you should output the leftmost digit of N N Input The input contains several test cases The f
  • Linux下进程内存空间组成/进程的内存映像

    http blog csdn net yusiguyuan article details 45155035 http javathinker iteye com blog 1733058 前言 在偏底层的开发中 需要了解程序的是如何存储的
  • ddl是什么意思网络语_DDL是什么意思

    1 It is necessary to accurately monitor location of gas water interface in annular between casing and test tube for pres
  • Java实现设计模式之——单例模式

    目录 1 什么是单例模式 2 单例模式的实现 2 1 饿汉式单例模式 2 2 懒汉式单例模式 3 线程安全的单例模式 3 1 版本 1 3 2 版本 2 双重检测 3 3 版本 3 禁止指令重排 1 什么是单例模式 单例模式是 Java 中
  • H2RBox:HORIZONTAL BOX ANNOTATION IS ALL YOU NEED FOR ORIENTED OBJECT DETECTION(读论文)

    H2RBOX HORIZONTAL BOX ANNOTATION IS ALL YOU NEED FOR ORIENTED OBJECT DETECTION 文章目录 H2RBOX HORIZONTAL BOX ANNOTATION IS
  • 拆分——nim游戏

    题目 给定 n 堆石子 两位玩家轮流操作 每次操作可以取走其中的一堆石子 然后放入两堆规模更小的石子 新堆规模可以为 0 且两个新堆的石子总数可以大于取走的那堆石子数 最后无法进行操作的人视为失败 问如果两人都采用最优策略 先手是否必胜 输
  • 三、Redis_12(笔记)

    文章目录 Redis Redisd的简介 Redisd的特点 NoSQL技术 Redis 的安装 Redis 的分类 Redis 的常 命令 基本命令 字符串相关命令 Hash 相关命令 List 相关命令 Set 相关命令 ZSet 相关
  • CKA真题分析-2023年度

    补充信息 补全 apt install bash completion source lt kubectl completion bash kubectl config get contexts cat kube config grep c
  • python 自定义类支持缓冲协议_Python编程技巧整理

    过滤列表中的数据 实际案例 过滤掉列表里面的负数 案例分析 filter function or None iterable py2返回一个列表 py3返回一个迭代器 列表解析 使用timeit来测试函数的运行时间 案例代码 python3
  • threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with

    异常描述 空值异常 java lang NullPointerException 这是因为我自己在拦截器拦截的时候进行的登录判断时通过session获取到一个空的user并使用这个实体类的getUserName方法获取用户名出现了错误 这是
  • C++ 作业 day1 7/14

    脑图
  • 性能监控-grafana+prometheus+node_exporter

    Prometheus是一个开源的系统监控和报警工具 它由SoundCloud开发并于2012年发布 后来成为了一个独立的开源项目 并得到了广泛的应用和支持 Prometheus的主要功能包括采集和存储各种系统和应用程序的监控数据 并提供强大
  • 基础算法题——学长的白日梦(快速幂、快速逐步求积)

    学长的白日梦 题目简单明了 只要将计算出 xi 即可 两个卡点 快速幂 快速逐步求积 由于这道题 mod 999999997 mod mod gt 10 19 不能直接用快速幂解决 中间求积会爆 于是我卡在逐步求余上动弹不得 唉 看了题解后
  • selenium找不到chrome浏览器的解决办法

    传入chrome exe的绝对路径 例如 options webdriver ChromeOptions options binary location C Program Files x86 Google Chrome Applicati
  • 关于RC电路特点以及几种常见的典型应用

    RC电路是由电阻R以及电容C组成的电路 只需要一个电阻R以及一个电容C 通过这两个器件的不同串并联 并选取不同的参数 可以实现几种不同的功能 RC电路在模拟电路 数字电路中得到了广泛的应用 R 的连接方式 RC 串联电路 电路的特点 由于有
  • mybatisplus group by 归组

    QueryWrapper
  • web前端文件上传可选择的4种方式

    在web前端开发中 文件上传属于很常见的功能 不论是图片 还是文档等等资源 或多或少会有上传的需求 一般都是从添加文件开始 然后读取文件信息 再通过一定的方式将文件上传到服务器上 以供后续展示或下载使用 本文将讲述文件上传中所能用到的4种添