前端如何上传文件???

410 阅读4分钟

提到文件上传就不得不表单的inputinput标签的属性type="file"的时候表示标签这是一个文件上传的表单项

<form action="./index.php" method="post">
  <input type="file" name="file" />
  <input type="submit" value="提交" />
</form>

当我们点击「选择文件」的时候浏览器会唤起选择文件的操作框,点击「提交」的时候会把表单数据直接发送到后端的接口(示例中./index.php

例如我选择一个文件后进行提交:

可以看到请求头里的数据格式是Content-Type: application/x-www-form-urlencoded,这表示是以「表单」的方式进行提交的,对表单数据进行序列号,这也是post请求默认的方式!!!(我们常用的axios工具库默认提交都是JSON的方式)

这个时候我们能发现,哎?不对啊,我刚才选择的不是一个文件吗?怎么Form Data里面只有一个文件的名字呢???

其实application/x-www-form-urlencoded请求数据的时候真正的样子是param1=xxx&param2=xxx,浏览器只是帮我们进行了美化,当我们点击view source的时候就能看到原始数据的格式

application/x-www-form-urlencoded格式请求接口的时候只能传输文本的数据,当我们上次一个文件的时候,请求找不到文本数据就只能找相应的标识,也就是文件名。

那么如何才能上传文件呢?

可以使用「二进制」的方式将文件分割为字符串进行传递。

form标签还有个属性enctype用来设置表单提交时的数据格式,我们只需要将enctype设置为multipart/form-data就可以传输文件了。

multipart/form-dataapplication/x-www-form-urlencoded都是表单的格式进行提交,只不过multipart/form-data可以传递文件,而enctype属性默认就是application/x-www-form-urlencoded

<form action="./index.php" method="post" enctype="multipart/form-data">
  <input type="file" name="file" />
  <input type="submit" value="提交" />
</form>

我这里没有后端服务只能将就着看了🥲

如何上传多个文件呢?

name的值设置为file[]就表示是一个数组,用来传递多个文件。

<form action="./index.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file[]" multiple />
    <input type="submit" value="提交" />
  </form>

FromData()

以上都是基于form进行的表单上传文件然后同步提交数据,而现在我们开发的时候基本上都是异步请求,那么如何使用Ajax进行上传文件呢?

再说Ajax上传文件之前,我们必须要认识一个构造函数FormData()

FormData()是表单form的表现方式,和Image()构造函数一样可以创建一个图片标签,FormData()用于创建一个表单标签。

var form = new FormData();

操作FormData必须使用实例方法:

append("name","value"):往表单里添加表单项

get("name"):获取表单数据

set("name","value"):设置表单数据

has("name") :查询是否存在某个表单项,返回布尔值

delete("name"):删除表单项

var formData = new FormData();
formData.append("user", "张三");
console.log(formData.get("user")); // 张三
formData.set("age", 20);
console.log(formData.has("age")); // true
formData.delete("age");
console.log(formData.has("age")); // false

需要特别注意的是直接打印formData是看不到任何数据的,必须使用get() 方法才能看到数据:

var formData = new FormData();
formData.append("user", "张三");
console.log(formData);
console.log(formData.get('user'));

Ajax 上传文件

接着上面的文件上传,我们需要有一个input来选择文件

<input type="file" name="file" id="file" />
var oFlie = document.getElementById("file");

oFlie.onchange = function (e){
  // this.files 所选文件的伪数组,每项包含文件的相关的信息,fileSize 是字节单位
  console.log(this.files)
}

然后我们就要实例化FormData()进行添加数据:

var oFlie = document.getElementById("file");

oFlie.onchange = function (e){
  var formData = new FormData();
  // file 是一个字段名,根据实际业务更改!!!
  formData.append("file", this.files[0]);
}

最后我们调用Ajax发送请求:

var oFlie = document.getElementById("file");

oFlie.onchange = function (e){
  var formData = new FormData();
  // file 是一个字段名,根据实际业务更改!!!
  formData.append("file", this.files[0]);
  
  requestAjax(formData);
}

function requestAjax(formData) {
  // 实例化 XMLHttpRequest()
  var xhr = new XMLHttpRequest();
  xhr.open("post", "./index.php");
  // 设置请求头
  xhr.setRequestHeader("Content-type", "multipart/form-data");
  xhr.send(formData);
  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status == 200) {
      alert("上传成功");
    } else {
      alert("上传失败");
    }
  };
}

这样就实现了一个简单的文件上传功能。

如果想要知道上传进度,我们还可以使用Ajax的进度事件onprogress

function requestAjax(formData) {
    var xhr = new XMLHttpRequest();
    xhr.open("post", "./index.php");
    // 设置请求头
    xhr.setRequestHeader("Content-type", "multipart/form-data");
    xhr.send(formData);
    // 在接收响应期间持续不断地触
    xhr.onprogress = function (e) {
      console.log(e.loaded); // 返回已经上传的字节数
      console.log(e.total); // 返回总的字节数
      var percent = (e.loaded / e.total) * 100 + "%";
      console.log("已上传:" + percent);
    };
    // onload 会在请求完成后触发
    xhr.onload = function () {
      // 对返回的 xhr.responseText 进行一些判断处理
      // ...
    };
  }