element UI FormData Blob 自定义文件上传

1,875 阅读4分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

FormData

XMLHttpRequest是一个浏览器接口,通过XMLHttpRequest可以使js进行http/https通信,是一种常用的前后端交互数据的方式。

FormData是XMLHttpRequest Level 2新增的一个对象,利用FormData来提交表单、模拟表单的提交,最大的优势是可以上传二进制文件。

作用:

1.模拟HTML表单,将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。

2.异步上传二进制文件。

formdata对象不能用于get请求,因为对象需要被传递到send方法中,而get请求方式请求的参数只能放在请求地址的后面。

以键值对的形式储存数据,类似Map。添加键值对主要使用set("key",value)或append("key",value)。其中,set与append的区别在于,当第一次的key与第二次的key相同时,set会覆盖第一次value中的数据,append会追加到value之后。

当多文件上传时,需要使用append追加数据。

Blob

对于Blob的介绍:直接浏览器搜索-利用Blob进行文件上传的完整步骤-文章即可。

Blob上传文件

Blob用于文件分片上传:

1.分片与并发结合,将一个大文件分割成多块,并发上传,极大的提高大文件的上传速度。分片传输能够更加实时的跟踪上传进度。

2.当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。

处理逻辑:

获取要上传文件的File对象,根据chunk(每片大小)对文件进行分片。通过post方法轮循上传每片文件,其中url中拼接querystring用于描述当前上传的文件信息。post body中存放本次要上传的二进制数据片段,接口每次返回offset,用于执行下次上传。

Blob下载文件

Blob可以处理很多类型的文件,可以控制从接收到二进制文件流到转化到Blob到用其他API来实现文件下载。可以在拿到二进制流文件到下载文件之间做个性化操作。

将responseType设置为Blob,就能将拿到的二进制文件转化为Blob,然后进行下载操作。

下载操作:

对于a标签,点击会跳转至href指定的地址。添加一个download属性后,则会去href属性指定的url下载文件(同源)。

在浏览器端,实现文件下载,无非就是借助a标签来指向一个URL地址。所以,在拿到二进制文件对应的Blob对象后,需要为这个Blob对象创建一个指向它的下载地址URL。

有两种方法:URL.createObjectURL和FileReader。

URL.createObjectURL

URL.createObjectURL方法可以实现接收File或Blob对象,创建一个DOMString,包含了对应的URL,指向File或Blob对象。

new Blob()存放二进制资源,window.URL.createObjectURL()会将 Blob存放的二进制资源转为url地址。

参考博客:blog.csdn.net/m0_51431448…

下载步骤:

1.首先通过 document.createElement('a') 创建一个a标签,用link来接受。

2.通过 link.setAttribute('download', 'filename.html') 或者直接 link .download = 'filename.html' 给a标签添加download属性。

3.通过 window.URL.createObjectURL 将 blob二进制资源 转为 url地址并赋给link.href

4.然后 执行 link.click() 即可下载。

FileReader

FileReader对象也可以对Blob对象生成一个下载地址URL。

下载过程主要由readAsDataURL和onload函数完成。readAsDataURL主要将File或Blob对象转为对应的URL,onload用于接收readAsDataURL完成的URL,在e.target.result上。

定义接口时,需要将responseType设置为blob。

定义接口XXX.js:

...
exportFile(params) {
    return Axios.post(URL, params, {
        responseType: 'blob',
    });
}
...

使用接口:

...
<button type="primary" @click="downLoadFile">下载文件</button>
...
import API form "XXX"
...
downLoadFile(param, fileName) {
                let downLoadParam ={
                    param, 
                    fileName
                };
                API.exportFile(downLoadParam).then(res => {
                    let blob = res.data;
                    let reader = new FileReader();
                    reader.readAsDataURL(blob);
                    reader.onload = (e) => {
                        let a = document.createElement('a');
                        a.download = fileName;
                        a.href = e.target.result;
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);
                    }
                });
}

element UI 自定义多文件上传

步骤:引入element UI->element UI属性设置->封装参数->调用接口

<template>
  <div>
    <div class="file-upload-container">
      <span class="file-upload-title">上传附件</span>
      <el-upload class="upload-demo" ref="itemUpload" action="#" :auto-upload="false" :http-request="uploadRequest">
          <el-button size="small" type="primary">点击上传</el-button>
          <!-- 已有文件显示 -->
          <div slot="tip" class="el-upload__tip">
              <ul class="el-upload-list el-upload-list--text">
                  <li tabindex="0" class="el-upload-list__item is-ready" v-for="(item, index) in fileList" :key="index">
                      <a class="el-upload-list__item-name">
                          <i class="el-icon-document"></i>
                          {{ item.fileName }}
                      </a>
                      <label class="el-upload-list__item-status-label"><i class="el-icon-upload-success el-icon-circle-check"></i></label>
                      <i class="el-icon-close" @click="deleteFile(item, index)"></i>
                  </li>
              </ul>
          </div>
      </el-upload>
  </div>
  <el-button type="primary" @click="uploadFile">上传至服务器</el-button>
  </div>
</template>
...
data() {
    return {
      fileList: [],
      uploadFileList: []
    };
  },
  methods: {
    // 获取上传的文件对象
    uploadRequest(item){
      console.log(item);
      this.uploadFileList.push(item.file);
      // 如果需要更改文件名字
      // let file = new File([file], '更改名字前缀_' + fileName, {type: file.type});
      // this.uploadFileList.push(file);
    },
    // 收到上传文件,调用接口
    uploadFile(){
      // uploadFileList清空
      this.uploadFileList = [];
      // 获取上传的文件,当调用this.$refs.itemUpload.submit(),uploadRequest方法则运行,uploadFileList存放上传的文件信息.
      this.$refs.itemUpload.submit();
      // 创建formData实例
      let formData = new FormData();
      // 封装参数,先遍历uploadFileList(多文件上传)
      this.uploadFileList.forEach((value)=>{
        formData.append('file',value)
      })
      // 其他参数对象
      formData.append('params',new Blob([JSON.stringify(params)],{type: 'application/json'}));
      // 调用文件上传接口,参数为formData.
      XXX(formData)
    }
  }
...

设置为手动上传时,需要将自动上传设置为false

:auto-upload="false"

:http-request="uploadRequest"中uploadRequest方法,在this.$refs.itemUpload.submit()后,会调用该方法,返回上传的文件对象信息。将file信息存储在定义的数组中并使用。

image.png

更多的属性可以查看element UI官网:element.eleme.cn/#/zh-CN/com…