提到文件上传就不得不表单的input
,input
标签的属性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¶m2=xxx
,浏览器只是帮我们进行了美化,当我们点击view source
的时候就能看到原始数据的格式
application/x-www-form-urlencoded
格式请求接口的时候只能传输文本的数据,当我们上次一个文件的时候,请求找不到文本数据就只能找相应的标识,也就是文件名。
那么如何才能上传文件呢?
可以使用「二进制」的方式将文件分割为字符串进行传递。
form
标签还有个属性enctype
用来设置表单提交时的数据格式,我们只需要将enctype
设置为multipart/form-data
就可以传输文件了。multipart/form-data
和application/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
必须使用实例方法:
:::info
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 进行一些判断处理
// ...
};
}