提到文件上传就不得不表单的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")); // trueformData.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 进行一些判断处理// ...};}
