一文带你吃透前端文件上传与文件相关操作

主要实现功能:单/多文件上传,分片上传,断点续传

学习视频"三十的前端课"

两种方案:

二进制blob传输 使用formData传输

base64 把文件转为base64传输

传输的模式关系:file类实际上继承于Blob类,可以使用Blob的方法

搭建页面

使用input实现文件上传

<template>
  <div>
    <form actions="/xxx" method="post" enctype="multipart/form-data"></form>
    <input
      type="file"
      ref="uploader"
      name="file"
      multiple
      @change="filesChange($event)"
    />
    <button @click="submits()">提交</button>
    <br />
    <img :src="imgUrl" style="width: 200px" alt="" />
    <br />
    <h3>上传进度{{ precent }}%</h3>
  </div>
</template>

<script>
import axios from "axios";
export default {
  name: "myFile",
  data() {
    return {
      imgUrl: "",
      myfile: {},
      fileList: [],
      precent: 0,
    };
  },
  
};
</script>

<style lang="scss" scoped></style>

1.单文件上传

formData对象上的append(key,value)方法可以添加额外的参数,比如name,age等,

使用fileReader把选中的图片文件转为base64格式,设置img标签的src属性为这个转换后的base64格式的imgUrl,就可以实现回显功能,如果对文件使用slice方法进行切割,就只能回显图片的小部分内容

filesChange(e) {
	  //获取选择到的第一个文件
      let file = e.target.files[0];
      this.myfile = file;
      if (file.size > 10 * 1024 * 1024) {
        alert("文件最大为10MB");
      }
      if (file.type !== "image/jpeg") {
        alert("图片格式必须是img");
      }
      //Blob对象使用slice方法来对文件进行裁剪,file也可以直接调用slice方法
      //注意Blob和File两个类的相互转换,第一个参数必须在数组里面
      let _sliceBlob = new Blob([file]).slice(0, 5000);
      let _sliceFile = new File([_sliceBlob], "test.png");
      let fr = new FileReader();
     //转为base64格式,也可以使用fr.readAsText()转为文本
      fr.readAsDataURL(file);
      let self = this;
      //转换方法是一个异步操作,后续操作必须使用fr.onload事件处理
      fr.onload = function () {
        self.imgUrl = fr.result;
      };
      //至此已经可以实现缩略图,和文本预览
    },
 async submit() {
      let _formData = new FormData();
      _formData.append("file", this.myfile);
      _formData.append("user", "Zhang San");
      axios.post("/xx", _formData);
    },

注意:使用formDta传参必须给请求头需要为Content-Type:multipare/form-data 

查看请求头的格式,分割线

浏览器会自动设置请求头Content-Type:multipare/form-data,不需要手动设置

请求的参数 如果想看传输的具体内容可以使用抓包工具进行抓包

2.多文件上传

使用fileList存储多个文件,如果上传的是多个文件就解构e.target.files并push到数组里面,如果是单个文件就直接push进数组,然后循环遍历数组发送请求即可

filesChange(e) {
      //可以选取多个文件时
      if (e.target.files.length > 1) {
        //多个文件
        this.fileList.push(...e.target.files);
      } else {
        //单个文件直接push就可以
        this.fileList.push(e.target.files[0]);
        this.myfile = e.target.files[0];
      }
    },
 //多文件上传
async submits() {
      this.fileList.forEach((item) => {
        let _formData = new FormData();
        _formData.append(item.name + "file", item);
        _formData.append("user", "Zhang San");
        axios.post("/xx", _formData);
      });
    },

3.分片上传,断点续传

filesChange(e) {
        //以单个文件上传为例,可以改为多个文件
      this.myfile = e.target.files[0];
    },
//分片上传,断点续传,
    async submits3() {
       //限制单次传输的分片大小为2MB 
      let size = 2*1024*1024;
      let fileSize = this.myfile.size;
      let current = 0;
      
      if (localStorage.getItem(this.myfile.name) !== null) {
        current = localStorage.getItem(this.myfile.name);
      }
      while (current < fileSize) {
        let _formData = new FormData();
        _formData.append(
          this.myfile.name,
          this.myfile.slice(current, current + size)
        );
        try {
          await axios.post("http://localhost:4000/upload", _formData);
          this.precent = Math.min(
            ((current * 100) / fileSize) * 100 * 100,
            100
          );
          current += size;
        } catch (error) {
            //如果出现异常情况,保存上次传输的current位置,并且设置key为文件名字,
            //如果下次传输的文件相同,就采用current的上次保存的位置
            localStorage.setItem(this.myfile.name, current);
        }
      }
    },

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值