浏览器上传图片到服务器时通过input type="file" 以及onchange事件的配合实现的,element和vant的ui库的图片上传都是基于这个
input的files属性
1.众所周知,一级dom事件不同于addeventlisner这种,它的function中的this指向当前事件对象
具体来说 addEventListener与onclick这种的区别就是this
不过好像也不需要this来指出dom,因为e身上就有target和srcElement,这个就是当前触发的dom。。。。
let b = document.getElementById('b')
let a = document.getElementById('a')
b.addEventListener('click', e => {
console.log(e, this);//事件对象 window
})
a.onclick = function (e) {
console.log(e, this);//事件对象, 当前dom
}
回来正题,然后获取input元素后会发现,input元素身上比其他元素多一个files属性,这个是用来放选择上传的文件的,文件列表
可以通过打印console.dir(this)来看元素详情,
如果给input元素添加multiple属性,那么就可以多选上传文件,不过如果第一次选了两个文件,第二次又选了一个文件,每一次的选择都会覆盖前面的
所以这个多选指的是一次可以选择多个上传
方式1,file
file方式主要是通过FormData()格式化数据,不设置请求头,
这样浏览器就会根据传入的data来判断contentType,formdata应该是二进制的
所以可以看到传输的方式是binary二进制的
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file" id="inputa" multiple>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script>
// file方式主要是通过FormData()格式化数据
// multipart/form-data; boundary=
let inputa = document.getElementById("inputa")
inputa.onchange = function () {
// this是input元素 this.files是选择的文件列表
let fd = new FormData()
console.log(this.files)
// files文件列表无法通过普通数组等循环遍历,需要通过迭代器循环遍历
for (let file of this.files) {
console.log('object', file)
fd.append(file.name, file)
}
// 循环把文件列表的文件添加到formdata中
console.log(fd)
$.ajax({
url: "http://localhost/upload",//请求路径
type: "POST",
data: fd,
dataType: 'JSON',
// contentType: "application/x-www-form-urlencoded",
contentType: false,//不设置请求头,
// 这样浏览器就会根据传入的data来判断contentType,
// 所以可以看到传输的方式是binary二进制的
processData: false,//同上同理
success(data) {
if (200 == data.code) {
console.log("上传成功!");
console.log(data)
} else {
console.log("上传失败!");
console.log(data)
}
},
error() {
console.log("与服务器通信发生错误");
}
})
}
</script>
</body>
</html>
后端
const multiparty = require("multiparty");
router.post('/upload', function (req, res) {
// 1.根据传过来的base64,以及要改成的名字,动态存入图片
console.log('req', req.body, req.request);
let form = new multiparty.Form({ uploadDir: './public/img' })
form.parse(req, function (err, filed, files) {
console.log(filed, files)
// let dataBuffer = new Buffer(filed, 'filed');
// console.log(dataBuffer)
})
res.send({ img: 'imgsrc' })
})
这里有两个点
1.如果contentType如图不设置,那么后端就需要通过multiparty来接收和存储文件,因为后端的req.body中不会有值,空的
图示
可以看到req.body为空
2.而如果设置成application/x-www-form-urlencoded,那么后端的req.body中会有相应的二进制值
可以看到req.body为一堆乱码二进制