web开发之文件上传的多种实现方式(附代码)

web开发之文件上传的多种实现方式(附代码)

文件上传是 web 开发常见需求,上传文件需要用到文件输入框,如果给文件输入框添加一个 multiple 属性则可以一次选择多个文件(不支持的浏览器会自动忽略这个属性)


点击这个输入框就可以打开浏览文件对话框选择文件了,一般一个输入框上传一个文件就行,要上传多个文件也可以用多个输入框来处理,这样做是为了兼容那些不支持 multiple 属性的浏览器,同时用户一般也不会选择多个文件

(推荐学习:HTML视频教程 ) 

基本上传方式

当把文件输入框放入表单中,提交表单的时候即可将选中的文件一起提交上传到服务器,需要注意的是由于提交的表单中包含文件,因此要修改一下表单元素的 enctype 属性为 multipart/form-data

    

这样上传方式是传统的同步上传,上传的文件如果很大,往往需要等待很久,上传完成后页面还会重新加载,并且必须等待上传完成后才能继续操作

早期的浏览器并不支持异步上传,不过可以使用 iframe 来模拟,在页面中隐藏一个

    

这样在提交表单上传的时候,页面就不会重新加载了,取而代之的是 iframe 重新加载了,不过 iframe 原本就是隐藏的,即使重新加载也不会感知到

访问文件

File API 提供了访问文件的能力,通过输入框的 files 属性访问,这会得到一个 FileList,这是一个集合,如果只选择了一个文件,那么集合中的第一个元素就是这个文件

var input = document.querySelector('input[type="file"]')var file = input.files[0]console.log(file.name) // 文件名称console.log(file.size) // 文件大小console.log(file.type) // 文件类型

支持 File API 的浏览器可以参考 caniuse

Ajax 上传

由于可以通过 File API 直接访问文件内容,再结合 XMLHttpRequest 对象直接将文件上传,将其作为参数传给 XMLHttpRequest 对象的 send 方法即可

var xhr = new XMLHttpRequest()xhr.open('POST', '/upload/url', true)xhr.send(file)

不过一些原因不建议直接这样传递文件,而是使用 FormData 对象来包装需要上传的文件,FormData 是一个构造函数,使用的时候先 new 一个实例,然后通过实例的 append 方法向其中添加数据,直接把需要上传的文件添加进去

var formData = new FormData()formData.append('file', file, file.name) // 第 3 个参数是文件名称formData.append('username', 'Mary') // 还可以添加额外的参数

甚至也可以直接把表单元素作为实例化参数,这样整个表单中的数据就全部包含进去了

var formData = new FormData(document.querySelector('form'))

数据准备好后,就是上传了,同样是作为参数传给 XMLHttpRequest 对象的 send 方法

var xhr = new XMLHttpRequest()xhr.open('POST', '/upload/url', true)xhr.send(formData)

监测上传进度

XMLHttpRequest 对象还提供了一个 progress 事件,基于这个事件可以知道上传进度如何

var xhr = new XMLHttpRequest()xhr.open('POST', '/upload/url', true)xhr.upload.onprogress = progressHandler // 这个函数接下来定义

上传的 progress 事件由 xhr.upload 对象触发,在事件处理程序中使用这个事件对象的 loaded(已上传字节数) 和 total(总数) 属性来计算上传的进度

function progressHandler(e) {  var percent = Math.round((e.loaded / e.total) * 100)}

上面的计算会得到一个表示完成百分比的数字,不过这两个值也不一定总会有,保险一点先判断一下事件对象的 lengthComputable 属性

function progressHandler(e) {  if (e.lengthComputable) {    var percent = Math.round((e.loaded / e.total) * 100)  }}

支持 Ajax 上传的浏览器可以参考 caniuse https://caniuse.com/#feat=xhr2

分割上传

使用文件对象的 slice 方法可以分割文件,给该方法传递两个参数,一个起始位置和一个结束位置,这会返回一个新的 Blob 对象,包含原文件从起始位置到结束位置的那一部分(文件 File 对象其实也是 Blob 对象,这可以通过 file instanceof Blob 确定,Blob 是 File 的父类)

var blob = file.slice(0, 1024) // 文件从字节位置 0 到字节位置 1024 那 1KB

将文件分割成几个 Blob 对象分别上传就能实现将大文件分割上传

function upload(file) {  let formData = new FormData()  formData.append('file', file)  let xhr = new XMLHttpRequest()  xhr.open('POST', '/upload/url', true)  xhr.send(formData)}var blob = file.slice(0, 1024)upload(blob) // 上传第一部分var blob2 = file.slice(1024, 2048)upload(blob2) // 上传第二部分// 上传剩余部分

通常用一个循环来处理更方便

var pos = 0 // 起始位置var size = 1024 // 块的大小while (pos < file.size) {  let blob = file.slice(pos, pos + size) // 结束位置 = 起始位置 + 块大小  upload(blob)  pos += size // 下次从结束位置开始继续分割}

服务器接收到分块文件进行重新组装的代码就不在这里展示了

使用这种方式上传文件会一次性发送多个 HTTP 请求,那么如何处理这种多个请求同时发送的情况呢?方法有很多,可以用 Promise 来处理,让每次上传都返回一个 promise 对象,然后用 Promise.all 方法来合并处理,Promise.all 方法接受一个数组作为参数,因此将每次上传返回的 promise 对象放在一个数组中

var promises = []while (pos < file.size) {  let blob = file.slice(pos, pos + size)  promises.push(upload(blob)) // upload 应该返回一个 promise  pos += size}

同时改造一下 upload 函数使其返回一个 promise

function upload(file) {  return new Promise((resolve, reject) => {    let formData = new FormData()    formData.append('file', file)    let xhr = new XMLHttpRequest()    xhr.open('POST', '/upload/url', true)    xhr.onload = () => resolve(xhr.responseText)    xhr.onerror = () => reject(xhr.statusText)    xhr.send(formData)  })}

当一切完成后

Promise.all(promises).then((response) => {  console.log('Upload success!')}).catch((err) => {  console.log(err)})

支持文件分割的浏览器可以参考 caniuse

判断一下文件对象是否有该方法就能知道浏览器是否支持该方法,对于早期的部分版本浏览器需要加上对应的浏览器厂商前缀

var slice = file.slice || file.webkitSlice || file.mozSliceif (slice) {  let blob = slice.call(file, 0, 1024) // call  upload(blob)} else {  upload(file) // 不支持分割就只能直接上传整个文件了,或者提示文件过大}

拖拽上传

通过拖拽 API 可以实现拖拽文件上传,默认情况下,拖拽一个文件到浏览器中,浏览器会尝试打开这个文件,要使用拖拽功能需要阻止这个默认行为

document.addEventListener('dragover', function(e) {  e.preventDefault()  e.stopPropagation()})

任意指定一个元素来作为释放拖拽的区域,给一个元素绑定 drop 事件

var element = document.querySelector('label')element.addEventListener('drop', function(e) {  e.preventDefault()  e.stopPropagation()  // ...})

通过该事件对象的 dataTransfer 属性获取文件,然后上传即可

var file = e.dataTransfer.files[0]upload(file) // upload 函数前面已经定义

选择类型

给文件输入框添加 accept 属性即可指定选择文件的类型,比如要选择 png 格式的图片,则指定其值为 image/png,如果要允许选择所有类型的图片,就是 image/*


添加 capture 属性可以调用设备机能,比如 capture=”camera” 可以调用相机拍照,不过这并不是一个标准属性,不同设备实现方式也不一样,需要注意


经测 iOS 设备添加该属性后只能拍照而不能从相册选择文件了,所以判断一下

if (iOS) { // iOS 用 navigator.userAgent 判断  input.removeAttribute('capture')}

不支持的浏览器会自动忽略这些属性

自定义样式

文件输入框在各个浏览器中呈现的样子都不大相同,而且给 input 定义样式也不是那么方便,如果有需要应用自定义样式,有一个技巧,可以用一个 label 关联到这个文件输入框,当点击这个 label 元素的时候就会触发文件输入框的点击,打开浏览文件的对话框,相当于点击了文件输入框一样的效果

这时就可以将原本的文件输入框隐藏了,然后给 label 元素任意地应用样式,毕竟要给 label 元素应用样式比 input 方便得多

本文来自PHP中文网,html教程栏目,欢迎学习  

以上就是web开发之文件上传的多种实现方式(附代码)的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1548205.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月21日 19:48:31
下一篇 2025年12月21日 19:48:39

相关推荐

  • HTML怎么引入js文件?

    在html中可以使用标签,通过 src 属性来引入js文件。 标签用于定义客户端脚本,比如 javascript。 script标签元素既可以包含脚本语句,也可以通过 src 属性指向外部脚本文件。必需的 type 属性规定脚本的 MIME 类型。 示例: 建立一个外部的js文件(hello.js)…

    2025年12月21日
    000
  • html css js是什么?

    html称为超文本标记语言,是一种标识性的语言;css表示层叠样式表,是一种用来表现HTML或XML等文件样式的计算机语言;js全称为JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言。 在现今的互联网生活中,我们经常能看见CSS,HTML,js放在一起,却有很多人都…

    2025年12月21日
    000
  • js为什么那么难

    这个问题我就不等大家的回答了,相信大家也明白,我并不是闲的无聊这么问。js本身语法并不难,它困难的地方在哪呢?主要在于以下几点: 1,怎么样去把具象的问题抽象化 就是面对一个很具体的需求时,例如时,,一个网上商城吧,它内部的各种交互纷繁复杂。那么你是如何入手去写呢?前端架构也是需要设计的,这就看你是…

    2025年12月21日
    000
  • html5中怎么用js?

    在html5中可以直接在页面中嵌入JavaScript代码和包含外部JavaScript文件,嵌入脚本的语法是“”,外部脚本的语法是“”。 在html5中可以通过标签以两种方式(嵌入脚本和外部脚本)来使用js代码。下面本篇文章给大家介绍一下,希望对大家有所帮助。 在html5中使用js的两种方法: …

    2025年12月21日
    000
  • JS实现简易版贪吃蛇小游戏

    新建网页 //① 绘制地图 function Map() { //私有成员(不会随便发生变化) var w = 800; var h = 400; //成员方法,绘制地图 this.showmap = function () { //创建p、设置css样式、追加给body var tu = docu…

    好文分享 2025年12月21日
    000
  • 如何利用js拼接html字符串

    下面小编就为大家带来一篇js拼接html字符串的注意事项。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 +加好拼接如果不换行,是不会出现执行一段一段执行的情况,但是字符串太长了,换行之后会出现一段一段执行的情况,这样页面生成的p等就不是想要的结果了。 换行要这样拼接 …

    好文分享 2025年12月21日
    000
  • 如何用JS实现直接运行html的代码

    这篇文章主要介绍了js实现直接运行html代码的方法,涉及javascript窗口操作相关实现技巧,需要的朋友可以参考下 本文实例讲述了JS实现直接运行html代码的方法。分享给大家供大家参考,具体如下: 1、实例代码: 直接运行 html 代码 document.getElementById(‘b…

    2025年12月21日
    000
  • js+html5实现页面可刷新的倒计时效果

    这篇文章主要为大家详细介绍了js+html5实现页面可刷新的倒计时效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 写了一个5分钟倒计时的代码,有的时候代码需要刷新,然后倒计时又从4:59开始了,我想到的一个解决办法,就是使用缓存,将开始倒计时的时间加上要倒计时的5分钟设为缓存,然后直接用这个…

    好文分享 2025年12月21日
    000
  • js获取Html元素的实际宽度高度的方法

    下面小编就为大家带来一篇js获取html元素的实际宽度高度的方法。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 第一种情况就是宽高都写在样式表里,就比如#p1{width:120px;}。这中情况通过#p1.style.width拿不到宽度,而通过#p1.offsetW…

    好文分享 2025年12月21日
    000
  • JS实现加载时锁定HTML页面元素的方法

    这篇文章主要介绍了js实现加载时锁定html页面元素的方法,涉及javascript针对页面元素的遍历与属性操作相关实现技巧,需要的朋友可以参考下 本文实例讲述了JS实现加载时锁定HTML页面元素的方法。分享给大家供大家参考,具体如下: 在html加载时js锁定页面内所有input,textarea…

    好文分享 2025年12月21日
    000
  • JS实现改变HTML上文字颜色和内容的方法

    这篇文章主要介绍了js实现改变html上文字颜色和内容的方法,涉及js数学运算与页面元素动态操作相关技巧,需要的朋友可以参考下 本文实例讲述了JS实现改变HTML上文字颜色和内容的方法。分享给大家供大家参考,具体如下: 1. JavaScript Day 1 // to change the col…

    2025年12月21日
    000
  • css+html实现简单的日历

    这篇文章主要为大家详细介绍了由html、css、javascript结合实现的简单日历,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 web页面中很多地方都会用到日历显示,选择等,本文用html、css、javascript实现简单的日历。完成以后的效果与页面左侧的效果差不多,可以切换上个月、下…

    2025年12月21日
    000
  • Javascript操作dom对象之select(详细解答)

    下面我为大家带来一篇javascript操作dom对象之select全面解析。现在就分享给大家,也给大家做个参考。 html代码:   北京大学清华大学北京电影学院js原生操作 1.获取select对象; 立即学习“Java免费学习笔记(深入)”; var university=document.g…

    好文分享 2025年12月21日
    000
  • javascript 中Cookie读、写与删除操作(图文教程)

    这篇文章主要介绍了javascript 中cookie读、写与删除操作的相关资料,需要的朋友可以参考下  javascript 中Cookie读、写与删除操作 前言: 在这个前端横行的时候,页面之间的交互需要数据的传递,有的数据通过url传参的形式可以很好地解决,但是对于部分需要改变的参数,你如说从…

    好文分享 2025年12月21日
    000
  • 如何在HTML中使用JavaScript

    本篇文章主要介绍如何在html中使用javascript,感兴趣的朋友参考下,希望对大家有所帮助。 标签   在HTML5中script主要有以下几个属性:async,defer,charset,src,type, async(可选):     关键词:异步脚本,外部文件,立即下载; 立即学习“Ja…

    2025年12月21日
    000
  • 在HTML文档中嵌入JavaScript的四种方法

    本篇文章主要介绍了在html文档里嵌入客户端javascript代码有4中方法,感兴趣的小伙伴们可以参考一下,具体如下: 在HTML里嵌入JavaScript 在HTML文档里嵌入客户端JavaScript代码有4中方法: 1.内嵌,放置在和标签之间  (少); 2.放置在有标签的src属性指定的外…

    好文分享 2025年12月21日
    000
  • JavaScript与HTML的结合方法详解

    这篇文章主要介绍了javascript与html的结合方法,利用实例向大家介绍javascript与html是如何结合的,内容很详细,感兴趣的小伙伴们可以参考一下 HTML中的JavaScript脚本必须位于与标签之间,JavaScript脚本可被放置在HTML页面的 标签和标签中,这种视情况而定,…

    2025年12月21日
    000
  • HTML实现美化上传文件样式

    这篇文章介绍的内容是HTML实现美化上传文件i样式 ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 传统写法 上传文件 效果如下图所示 这个样式调整了很长时间,最后结果都不尽人意。 非常规写法 上传文件 上传 给真正的用于上传文件的Input style=’display:none;…

    2025年12月21日
    000
  • h5+js实现本地文件读取和写入

    这次给大家带来h5+js实现本地文件读取和写入,h5+js实现本地文件读取和写入的注意事项有哪些,下面就是实战案例,一起来看一下。 代码如下: 读取本地文件 Document //点击导入按钮,使files触发点击事件,然后完成读取文件的操作 $(“#fileImport”).click(funct…

    好文分享 2025年12月21日
    000
  • JavaScript数组-字符串-数学函数

    这次给大家带来javascript数组-字符串-数学函数,使用javascript数组-字符串-数学函数的注意事项有哪些,下面就是实战案例,一起来看一下。 数组方法里push、pop、shift、unshift、join、split分别是什么作用。push()方法添加一个或多个元素到数组的末尾,并返…

    好文分享 2025年12月21日
    000

发表回复

登录后才能评论
关注微信