表单补充
表单的enctype属性
enctype属性决定表单的编码格式,表单能够用三种编码,向服务器发送数据
- GET 方法
如果表单使用GET方法发送数据,enctype属性无效。数据将以 URL 的查询字符串发出
- POST方法
当使用 method 为 POST 时,可以指定属性 enctype
- application/x-www-form-urlencoded
如果表单用POST方法发送数据,并省略enctype属性,那么数据以application/x-www-form-urlencoded格式发送(因为这是默认值),提交的数据按照 key1=val1&key2=val2 的键值对方式进行编码,key 和 val 都进行了 URL 转码,大部分服务端语言都对这种方式很好的支持
- text/plain
如果表单使用POST方法发送数据,enctype属性为text/plain,那么数据将以纯文本格式发送。
- multipart/form-data
如果表单使用POST方法,enctype属性为multipart/form-data,那么数据将以混合的格式发送。这种格式也是文件上传的格式,指表单数据有多部分构成:既有文本数据,又有二进制文件等数据,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开
对于文件上传工作,其实是在前端完成的,即,在php,java等语言处理之前,文件其实就已经被上传到服务器了,服务器脚本语言的作用不过是将这些临时文件持久化而已
单文件上传
思考:文件如何上传?上传的数据格式?如何实现本地预览?如何接收数据展示列表?
目标:
FormReader
异步读取本地文件
常用方法:
readAsDataURL 转为base64
onload 读取文件操作完成时触发,返回参数中包含的target有成功转为base64的数据即event.target.result
步骤拆解
获取文件对象(通过input.files,前端选择文件的时候能够拿到文件的类型、名称、大小等具体信息)
判断兼容性(判断浏览器是否兼容HTML5)
Ajax发送post请求(主要使用FormData将文件转为二进制发送)
本地预览图片(主要使用FormReader将文件转为base64显示)
Ajsx发送get请求接收展示文件信息列表(此处的列表信息如果后端传的是完整url路径则前端可以显示图片,也可选择传图片名称即可)base64
<body>
<div>单文件上传:
<input type="file" id="file" value="" accept="image/*">
<img src="" id="myImg">
<button id="upload">上传</button>
</div>
<div class="lists">
</div>
</body>
let input = document.querySelector('#file')
let upload = document.querySelector('#upload')
let myImg = document.querySelector('#myImg')
let lists = document.querySelector('.lists')
const files = input.files ? input.files : []
upload.onclick = function() {
if (!files.length || !window.FileReader) {
console.log('浏览器不支持');
return false
}
// console.log(files)
}
upload.onclick = function() {
...
const fd = new FormData()
fd.append('file', files[0])
//发送post请求
const request = new XMLHttpRequest()
request.open('post', 'https://139.196.42.209.8001/upload/single')
request.send(fd)
request.onreadystatechange = function() {
if (request.readyState === 4 & request.status === 200) {
alert('上传成功!')
input.value = '' //清空表单值
myImg.src = '' //清空本地预览
list() //调用列表展示
}
}
}
注意:input为file类型时,value修改只能置空,不能设置为其他值
upload.onchange = function(e) {
// console.log(files)
const file = e.target.files[0]
console.log(file)
console.log(e.target)
const reader = new FileReader() //异步读取文件
reader.readAsDataURL(file) //转成base64 以便显示图片
reader.onload = function(event) {
myImg.src = event.target.result
}
}
function list() {
const request = new XMLHttpRequest()
request.open('get', 'https://139.196.42.209.8001/upload/list')
request.send()
request.onreadystatechange = function() {
if (request.readyState === 4 & request.status === 200) {
const res = JSON.parse(request.responseText)
const str = '<ul>'
res.list.forEach((item, i) => {
str += '<li>' + item + '<li>'
})
str += '</ul>'
lists.innerHTML = str
}
}
}
list()
思考:
如果没有添加accept="image/*"属性
限制范围,而是任意文件类型,则如何通过判断机制控制本地预览?
👉可以添加判断机制,file.type不是目标文件,如zip压缩文件等,可以添加一类默认图片展示
多文件上传
目标:
- 多选文件
- 多个图片展示
思路:
主要是利用multiple属性+for循环遍历
<body>
<div>单文件上传:
<input type="file" id="file" value="" accept="image/*" multiple>
<img src="" id="myImg">
<button id="upload">上传</button>
</div>
<div class="lists">
</div>
</body>
...
let fd = new FormData()
//之前单文件:fd.append('file',files[0])
//改成for循环:遍历每个文件
for(let i =0;i<files.length;i++){
fd.append('file',files[i])
}
input.onchange = function (e){
var imgs = document.querySelector("#imgs");
for (var i = 0; i < e.target.files.length; i++) {
var img=document.createElement("img"); //创建展位
img.width=100;
var file = e.target.files[i]; //获取当前文件
console.log(file);
if (!(/^image\/.*$/i.test(file.type))) {
continue; //不是图片 就跳出这一次循环
};
var thisSrc = URL.createObjectURL(file); //获取当前文件对象的地址
img.setAttribute('src', thisSrc);//动态添加图片属性
img.onload=function(){ //图片重新加载
imgs.append(this); //图片添加到列表中
URL.revokeObjectURL(thisSrc);//释放内存
}
}
}
大文件上传
采用分片上传的方式去上传,而blob提供了slice方法, file继承了blob自然也能使用slice去进行分片处理。
将文件切割成多个小块,然后每次只发送一小块,等到全部分片传输完毕之后,再发送一个合并请求,服务端将接受的多个小块进行合并,组成上传的文件,然后删除分片