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

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

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

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

这个时候我们能发现,哎?不对啊,我刚才选择的不是一个文件吗?怎么Form Data里面只有一个文件的名字呢???
其实application/x-www-form-urlencoded请求数据的时候真正的样子是param1=xxx&param2=xxx,浏览器只是帮我们进行了美化,当我们点击view source的时候就能看到原始数据的格式
image.png

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

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

image.png

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

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

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

FromData()

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

再说Ajax上传文件之前,我们必须要认识一个构造函数FormData()
FormData()是表单form的表现方式,和Image()构造函数一样可以创建一个图片标签,FormData()用于创建一个表单标签。

  1. var form = new FormData();

操作FormData必须使用实例方法: :::info append("name","value"):往表单里添加表单项
get("name"):获取表单数据
set("name","value"):设置表单数据
has("name") :查询是否存在某个表单项,返回布尔值
delete("name"):删除表单项 :::

  1. var formData = new FormData();
  2. formData.append("user", "张三");
  3. console.log(formData.get("user")); // 张三
  4. formData.set("age", 20);
  5. console.log(formData.has("age")); // true
  6. formData.delete("age");
  7. console.log(formData.has("age")); // false

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

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

image.png

Ajax 上传文件

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

  1. <input type="file" name="file" id="file" />
  1. var oFlie = document.getElementById("file");
  2. oFlie.onchange = function (e){
  3. // this.files 所选文件的伪数组,每项包含文件的相关的信息,fileSize 是字节单位
  4. console.log(this.files)
  5. }

image.png

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

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

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

  1. var oFlie = document.getElementById("file");
  2. oFlie.onchange = function (e){
  3. var formData = new FormData();
  4. // file 是一个字段名,根据实际业务更改!!!
  5. formData.append("file", this.files[0]);
  6. requestAjax(formData);
  7. }
  8. function requestAjax(formData) {
  9. // 实例化 XMLHttpRequest()
  10. var xhr = new XMLHttpRequest();
  11. xhr.open("post", "./index.php");
  12. // 设置请求头
  13. xhr.setRequestHeader("Content-type", "multipart/form-data");
  14. xhr.send(formData);
  15. xhr.onreadystatechange = function () {
  16. if (xhr.readyState == 4 && xhr.status == 200) {
  17. alert("上传成功");
  18. } else {
  19. alert("上传失败");
  20. }
  21. };
  22. }

这样就实现了一个简单的文件上传功能。
如果想要知道上传进度,我们还可以使用Ajax的进度事件onprogress

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