表单补充

表单的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等语言处理之前,文件其实就已经被上传到服务器了,服务器脚本语言的作用不过是将这些临时文件持久化而已

单文件上传

思考:文件如何上传?上传的数据格式?如何实现本地预览?如何接收数据展示列表?
目标:

  1. 选择文件—->点击上传文件—-> 向后端发起请求
  2. 点击上传文件—->本地预览当前文件
  3. 展示文件名称列表

    FormData

    将当前上传的文件转换为二进制数据的形式(流)
    常用方法:append

FormReader

异步读取本地文件
常用方法:
readAsDataURL 转为base64
onload 读取文件操作完成时触发,返回参数中包含的target有成功转为base64的数据即event.target.result

步骤拆解

获取文件对象(通过input.files,前端选择文件的时候能够拿到文件的类型、名称、大小等具体信息)
判断兼容性(判断浏览器是否兼容HTML5)
Ajax发送post请求(主要使用FormData将文件转为二进制发送)
本地预览图片(主要使用FormReader将文件转为base64显示)
Ajsx发送get请求接收展示文件信息列表(此处的列表信息如果后端传的是完整url路径则前端可以显示图片,也可选择传图片名称即可)
image.pngbase64

  1. <body>
  2. <div>单文件上传:
  3. <input type="file" id="file" value="" accept="image/*">
  4. <img src="" id="myImg">
  5. <button id="upload">上传</button>
  6. </div>
  7. <div class="lists">
  8. </div>
  9. </body>
  1. let input = document.querySelector('#file')
  2. let upload = document.querySelector('#upload')
  3. let myImg = document.querySelector('#myImg')
  4. let lists = document.querySelector('.lists')
  1. const files = input.files ? input.files : []
  1. upload.onclick = function() {
  2. if (!files.length || !window.FileReader) {
  3. console.log('浏览器不支持');
  4. return false
  5. }
  6. // console.log(files)
  7. }
  1. upload.onclick = function() {
  2. ...
  3. const fd = new FormData()
  4. fd.append('file', files[0])
  5. //发送post请求
  6. const request = new XMLHttpRequest()
  7. request.open('post', 'https://139.196.42.209.8001/upload/single')
  8. request.send(fd)
  9. request.onreadystatechange = function() {
  10. if (request.readyState === 4 & request.status === 200) {
  11. alert('上传成功!')
  12. input.value = '' //清空表单值
  13. myImg.src = '' //清空本地预览
  14. list() //调用列表展示
  15. }
  16. }
  17. }

注意:input为file类型时,value修改只能置空,不能设置为其他值
image.png

  1. upload.onchange = function(e) {
  2. // console.log(files)
  3. const file = e.target.files[0]
  4. console.log(file)
  5. console.log(e.target)
  6. const reader = new FileReader() //异步读取文件
  7. reader.readAsDataURL(file) //转成base64 以便显示图片
  8. reader.onload = function(event) {
  9. myImg.src = event.target.result
  10. }
  11. }
  1. function list() {
  2. const request = new XMLHttpRequest()
  3. request.open('get', 'https://139.196.42.209.8001/upload/list')
  4. request.send()
  5. request.onreadystatechange = function() {
  6. if (request.readyState === 4 & request.status === 200) {
  7. const res = JSON.parse(request.responseText)
  8. const str = '<ul>'
  9. res.list.forEach((item, i) => {
  10. str += '<li>' + item + '<li>'
  11. })
  12. str += '</ul>'
  13. lists.innerHTML = str
  14. }
  15. }
  16. }
  17. list()

思考:
如果没有添加accept="image/*"属性限制范围,而是任意文件类型,则如何通过判断机制控制本地预览?
👉可以添加判断机制,file.type不是目标文件,如zip压缩文件等,可以添加一类默认图片展示

多文件上传

目标:

  1. 多选文件
  2. 多个图片展示

思路:
主要是利用multiple属性+for循环遍历

  1. <body>
  2. <div>单文件上传:
  3. <input type="file" id="file" value="" accept="image/*" multiple>
  4. <img src="" id="myImg">
  5. <button id="upload">上传</button>
  6. </div>
  7. <div class="lists">
  8. </div>
  9. </body>
  1. ...
  2. let fd = new FormData()
  3. //之前单文件:fd.append('file',files[0])
  4. //改成for循环:遍历每个文件
  5. for(let i =0;i<files.length;i++){
  6. fd.append('file',files[i])
  7. }
  1. input.onchange = function (e){
  2. var imgs = document.querySelector("#imgs");
  3. for (var i = 0; i < e.target.files.length; i++) {
  4. var img=document.createElement("img"); //创建展位
  5. img.width=100;
  6. var file = e.target.files[i]; //获取当前文件
  7. console.log(file);
  8. if (!(/^image\/.*$/i.test(file.type))) {
  9. continue; //不是图片 就跳出这一次循环
  10. };
  11. var thisSrc = URL.createObjectURL(file); //获取当前文件对象的地址
  12. img.setAttribute('src', thisSrc);//动态添加图片属性
  13. img.onload=function(){ //图片重新加载
  14. imgs.append(this); //图片添加到列表中
  15. URL.revokeObjectURL(thisSrc);//释放内存
  16. }
  17. }
  18. }

大文件上传

采用分片上传的方式去上传,而blob提供了slice方法, file继承了blob自然也能使用slice去进行分片处理。
将文件切割成多个小块,然后每次只发送一小块,等到全部分片传输完毕之后,再发送一个合并请求,服务端将接受的多个小块进行合并,组成上传的文件,然后删除分片