宝子, 在你前端开发的过程中有没有遇到过文件上传的需求呢?
如果有这样的经历,那么邀请你花一点时间,以批判性的视角审视一下这篇文章。
正文开始
某一天,你在做一个后端管理项目,这时你收到一个需求,要求你的表单可以上传附件。那么, 表单的 input ✨ 就闪亮登场了。
我们只需在 input 中加入 type='file' 就可以使这个输入框变成一个文件选择器。
接着,我们点击文件选择器,选中了要上传的文件,那么我应该如何拿到这个文件呢?
前端的交互大量依赖事件机制,
于是我们要祭出我们的addEventListener。
首先对我们的表单元素进行事件绑定, 对应的事件是 change, 这个事件是用来监听[我们选择文件后确定的动作的], 而他的绑定事件监听器(回调函数)的事件对象(e或者event)中的 target.files 就是存放我们选择文件的数组。因为上传文件可以多选,所以是一个数组格式。代码如下:
<form>
<input type="file" id="fileInput"/>
</form>
<script>
const fileEl = document.getElementById("fileInput");
fileEl.addEventListener("change", e => {
const file = e.target.files[0]
})
</script>
此时, 文件[Object file]就已经拿到了, 那么如何传给服务端呢? 为了解决这个问题, new FormData 就要登场了。
new FormData() 是浏览器提供的内置构造函数,用于创建一个 FormData 对象,专门用来封装和管理表单数据的。
FormData 的使用有两种用法。
第一种是直接在 form 表单上设置
<form action="/upload" method="POST" enctype="multipart/form-data">
这样当你的表单 sumbit 的时候浏览器内部会帮你自动构建 FormData 数据并提交, 在此不做过多的讨论。
第二种是我们接下来要使用的方法,即使用 js 来实例化一个 FormData 数据并向服务端提交数据。
用法也很简单抓住两个关键点,一个是 new 实例化, 另一个是 append 的方法 插入数据。
你可以简单的理解为 FormData 就是键值对集合, 而插入数据的方法使用 append 而已。下面来看一下用例代码
<form>
<input type="file" id="fileInput"/>
</form>
<script>
const fileEl = document.getElementById("fileInput");
fileEl.addEventListener("change", e => {
const file = e.target.files[0]
const data = new FormData() // 实例化 FormData
data.append('file', file) // 将 file 数据添加
})
</script>
使用 FormData 的时候,我觉得有几点需要额外注意一下:
-
这个数据格式与 Map 不同, append 插入相同的 key 时, 值不会被覆盖,而是形成数组。 也就是说同一 Key 可以多次 append, 形成数组。
-
遍历顺序是顺序保存的。
-
允许的值有字符串、Blob、File
-
不能用 console.log 直接打印内容,可以使用 entires() 方法打印,如下所示
for (const [key, value] of formData.entries()) { console.log(key, value); }
然后调用后端给的接口,将数据发送到服务端就完成啦。😉
你以为到这里就结束了吗?
调用接口的时候还是有需要注意的地方的。
以 axios 为例子, 需要注意如下两个细节
export const postFile = (formData) => {
return http.post('/fs/upload/cos', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
}
第一,是设置 headers 的 ContentType ; 第二还是设置 headers 的 ContentType。
这里有消息说, axios 可以自动处理,亲爱的读者,你觉得会不会呢?
总结一下:
- 以 input 为入手点, 设置 type=file, 设置 id 用来绑定事件
- 绑定 input 的 change 事件, 在事件监听器中取到需要上传的文件 e.target.files ← 再次提醒: 这是个数组哦
- 实例化 new FormData , 插入数据 append('file', file) , 为提交前做准备
- 调用接口,比如 post → URL → data 参数→ 设置 headers 的 Content-Type' 为 'multipart/form-data'
至此文件上传的逻辑就告一段落了,
无论是写原生 JS ,还是用第三方UI组件库,把握住 target.files 和 new FormData 两个点就可以掌握文件上传技术并灵活运用了。
至于文件大小、格式校验,就属于 validate 的领域了, 可以单独封装方法、插件,在本文中不做讨论。
感兴趣的小伙伴可以留言、点赞、提问、批评💐
关注我,下一篇我们聊聊后端如何接收这份数据
再见👋🏻