JS可断点续传文件上传实现代码解析


Posted in Javascript onJuly 30, 2020

刚开始学习前端开发就碰到文件上传问题,还要求可断点续传。查了很多资料,发现H5的file API刚好可以满足我们的需求,也遇到了一些问题,于是记录下来为有同样需求的朋友提供一些帮助。

一、首先,为了引入文件对象,需要在H5页面上放置一个file类型的输入标签。

<input type="file" onchange="fileInfo()">

当选择文件之后显示文件相关信息:

function fileInfo() {
   let fileObj = document.getElementById('file').files[0];
   console.log(fileObj);
 }

我们获取到的对象本身是一个数组,这里只选择了一个文件,需要选择多个文件可在input标签添加multiple属性。现在我们打开浏览器控制台可以看到输出了文件的最后修改时间、文件大小和文件名等信息:

JS可断点续传文件上传实现代码解析

二、好了,当我们获取到选择的文件对象之后,现在需要把文件上传到服务器,可以模拟表单事件进行上传,需要引入FormData对象,其次,由于HTTP对文件上传大小的限制,所以要对文件切块上传,在服务器收到文件块之后拼接成一个整体,最后还需要一个进度条去显示上传进度。在理清了思路以后这就动手实现:

先在H5页面放置一个进度条,同时将选择文件改变的事件更换为上传文件块的函数upload(开始上传字节处),这里我们从第0个字节开始上传,也就是从头开始传:

 <input type="file" id="file" onchange="upload(0)">
 <progress id="progress" max="100" value="0"></progress>

然后来实现文件块的上传函数:

// 文件切块大小为1MB
const chunkSize = 1024 * 1024;

// 从start字节处开始上传
function upload(start) {
  let fileObj = document.getElementById('file').files[0];
  // 上传完成
  if (start >= fileObj.size) {
    return;
  }
  // 获取文件块的终止字节
  let end = (start + chunkSize > fileObj.size) ? fileObj.size : (start + chunkSize);
  // 将文件切块上传
  let fd = new FormData();
  fd.append('file', fileObj.slice(start, end));
  // POST表单数据
  let xhr = new XMLHttpRequest();
  xhr.open('post', 'upload.php', true);
  xhr.onload = function() {
    if (this.readyState == 4 && this.status == 200) {
      // 上传一块完成后修改进度条信息,然后上传下一块
      let progress = document.getElementById('progress');
      progress.max = fileObj.size;
      progress.value = end;
      upload(end);
    }
  }
  xhr.send(fd);
}

这里使用原生的JS向服务器发送请求,将文件切块使用函数slice(开始位置,结束位置),然后将文件块封装到FormData对象实现模拟表单的文件上传。后台我使用PHP接收数据,也可以使用其他后端语言:

<?php
  // 追加文件块
  $fileName = $_FILES['file']['name'];
  file_put_contents('files/' . $fileName, file_get_contents($_FILES['file']['tmp_name']), FILE_APPEND);
?>

在这里我新建了一个文件夹files,将上传的文件存放到这里。获取的文件块内容采用追加的形式FILE_APPEND。于是我们打开浏览器上传文件:

JS可断点续传文件上传实现代码解析

然后查看一下files文件夹下面是否接收到vscode.exe文件:

JS可断点续传文件上传实现代码解析

三、有了文件上传功能,接下来我们要实现断点续传功能。在上一步文件切块的基础上,断点续传变得非常简单,如果突然断网或者浏览器意外关闭,那么上传的是不完整的文件,我们只需要在选择了文件以后向服务器查询一下服务器上相同文件名的大小,然后将开始上传位置(字节)设置到这个大小即可:

先定义一个初始化函数当选择文件后向服务器查询已上传文件大小:

// 初始化上传大小
function init() {
  let fileObj = document.getElementById('file').files[0];
  let xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      // 将字符串转化为整数
      let start = parseInt(this.responseText);
      // 设置进度条
      let progress = document.getElementById('progress');
      progress.max = fileObj.size;
      progress.value = start;
      // 开始上传
      upload(start);
    }
  }
  xhr.open('post', 'fileSize.php', true);
  // 向服务器发送文件名查询大小
  xhr.send(fileObj.name);
}

在服务器端使用fileSize.php查询已上传文件大小:

<?php
  // 接收文件名
  $fileName = file_get_contents('php://input');
  $fileSize = 0;
  $path = 'files/' . $fileName;
  //查询已上传文件大小
  if (file_exists($path)) {
    $fileSize = filesize($path);
  }
  echo $fileSize;
?>

最后将H5页面上input标签的onchange事件改为init():

<input type="file" onchange="init()">

同时upload函数也不需要重复设置进度条的最大值,修改为:

 // 上传一块完成后修改进度条信息,然后上传下一块

 document.getElementById('progress').value = end;

 upload(end);

然后打开浏览器,在上传过程中故意关闭浏览器下次再选择同一文件时即可从断点位置开始续传。

四、虽然已经实现了可断点续传的文件上传功能,但是界面还需要美化一下,这里引用bootstrap框架,需要jquery,顺便用jquery的ajax代替原生JS的ajax,需要注意的是$.ajax的processData和contentType属性都要设置成false:

// POST表单数据
$.ajax({
  url: 'upload.php',
  type: 'post',
  data: fd,
  processData: false,
  contentType: false,
  success: function() {
    upload(end);
  }
});

最后美化完成的效果图如下:

JS可断点续传文件上传实现代码解析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Prototype 学习 工具函数学习($w,$F方法)
Jul 12 Javascript
JavaScript访问样式表代码
Oct 15 Javascript
javascript 使td内容不换行不撑开
Nov 29 Javascript
javascript中键盘事件用法实例分析
Jan 30 Javascript
jQuery实现的简洁下拉菜单导航效果代码
Aug 26 Javascript
基于jQuery实现的向下滑动二级菜单效果代码
Aug 31 Javascript
如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
Dec 26 Javascript
深入对Vue.js $watch方法的理解
Mar 20 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)
Jan 24 Javascript
浅谈layui 表单元素的选中问题
Oct 25 Javascript
原生JS实现烟花效果
Mar 10 Javascript
javascript设计模式 ? 桥接模式原理与应用实例分析
Apr 13 Javascript
Vue单文件组件开发实现过程详解
Jul 30 #Javascript
vue实现从外部修改组件内部的变量的值
Jul 30 #Javascript
在vue中实现嵌套页面(iframe)
Jul 30 #Javascript
Vue文本模糊匹配功能如何实现
Jul 30 #Javascript
VUE 单页面使用 echart 窗口变化时的用法
Jul 30 #Javascript
解决vue单页面多个组件嵌套监听浏览器窗口变化问题
Jul 30 #Javascript
Vue Render函数原理及代码实例解析
Jul 30 #Javascript
You might like
无法载入 mcrypt 扩展,请检查 PHP 配置终极解决方案
2011/07/18 PHP
PHP常见的几种攻击方式实例小结
2019/04/29 PHP
jQuery弹出层插件简化版代码下载
2008/10/16 Javascript
javascript里模拟sleep(两种实现方式)
2013/01/25 Javascript
Flexigrid在IE下不显示数据的处理的解决方法
2013/10/24 Javascript
jQuery学习之prop和attr的区别示例介绍
2013/11/15 Javascript
为什么Node.js会这么火呢?Node.js流行的原因
2014/12/01 Javascript
JS获取Table中td值的方法
2015/03/19 Javascript
JavaScript测试工具之Karma-Jasmine的安装和使用详解
2015/12/03 Javascript
jQuery移动web开发之页面跳转和加载外部页面的实现
2015/12/04 Javascript
jquery操作select元素和option的实例代码
2016/02/03 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
详解nodejs模板引擎制作
2017/06/14 NodeJs
JavaScript实现的搜索及高亮显示功能示例
2017/08/14 Javascript
JS数组求和的常用方法总结【5种方法】
2019/01/14 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
2019/02/10 Javascript
vue获取时间戳转换为日期格式代码实例
2019/04/17 Javascript
[51:36]EG vs VP 2018国际邀请赛淘汰赛BO3 第一场 8.24
2018/08/25 DOTA
Python实现的Kmeans++算法实例
2014/04/26 Python
python实践项目之监控当前联网状态详情
2019/05/23 Python
Python pandas RFM模型应用实例详解
2019/11/20 Python
使用CSS3在触屏上为按钮实现激活效果
2013/09/27 HTML / CSS
Html5 页面适配iPhoneX(就是那么简单)
2019/09/05 HTML / CSS
业务代表的岗位职责
2013/11/16 职场文书
创业计划书中包含的9个方面
2013/12/26 职场文书
《列夫托尔斯泰》教学反思
2014/02/10 职场文书
党的群众路线教育实践活动心得体会900字
2014/03/07 职场文书
低碳环保倡议书
2014/04/14 职场文书
学校四风问题对照检查材料思想汇报
2014/09/26 职场文书
土地转让协议书
2014/09/27 职场文书
小鞋子观后感
2015/06/05 职场文书
《岳阳楼记》原文、译文赏析
2019/09/10 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
用position:sticky完美解决小程序吸顶问题的实现方法
2021/04/24 HTML / CSS
SQL CASE 表达式的具体使用
2022/03/21 SQL Server
python playwright之元素定位示例详解
2022/07/23 Python