一次理清前端文件上传操作(单个,多个,大文件切片)

这篇具有很好参考价值的文章主要介绍了一次理清前端文件上传操作(单个,多个,大文件切片)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

相信大家在工作中也会遇到前端文件上传的需求,虽然已经在项目中使用FormData和elementUI中upload组件都实现过类似上传效果,但自己对这块一直一知半解,因此做一个笔记梳理一下前端方面的文件上传操作,以供日常参考。

总体来说常用的两种方式:二进制传输和base64格式直接传输

正文开始之前先简单认识一下文件上传的四个相关对象,以便后续阅读代码更直观:

1、认识文件上传的四个相关对象

前端批量上传文件,前端,javascript,vue.js

1.files对象:

可以通过指定input标签type属性为file来读取files对象,是一个由一个或多个文件对象组成的数组。同时也是blob对象的子类,继承了一些blob对象的方法

2.blob对象:

表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。Blob 通常是影像、声音或多媒体文件。在 JavaScript 中 Blob 类型的对象表示不可变的类似文件对象的原始数据, 使用构造函数创建。

3.formData对象:

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

作用1:模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。
作用2:异步上传二进制文件。

4.fileReader对象

构造函数方式实例化一个fileReader对象,readAs()方法将文件对象读取成base64格式或者文本格式

2、二进制blob对象传输

上传时将文件转为blob对象,通过FormData对象搭载传递

使用vue-cli搭建了一个基础框架,代码如下

2.1文件上传前的判断操作

  <div>
    <p>file组件</p>
    <input type="file" @change="fileChange" multiple>
    <button @click="submit">提交</button>
  </div>
 
</template>

<script>
export default {
  data(){
    return{
      fileList:[],
      imgsrc:'',
      precent:0
    }
  },
  methods:{
  	//files对象的第一个应用:文件上传之前的大小和类型判断
    fileChange(e){
      console.log(e.target.files);//一个由不同文件对象组成的对象
      let files = e.target.files;
      
      //文件大小判断和文件类型判断 //假设不能大于10M
      if(files[0].size > 10*1024*1024){
        alert('文件不能大于10M')
      }else if(files[0].type != "application/pdf"){
        alert("文件类型必须是pdf格式")
      }
      
    },
    async submit(){
	
    }
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

console.log(e.target.files)打印结构如下:
前端批量上传文件,前端,javascript,vue.js
由此可见其是一个由多个文件对象组成的对象,每个文件对象内部又有多个属性,比较常用size和type属性做文件上传之前的大小和类型判断。

2.2files与blob转换 缩略图和文本预览

files对象与blob对象的相互转换和blob对象的切割方法 :项目中实现缩略图和文本预览


  methods:{
    fileChange(e){
      let files = e.target.files[0];
     
      let _newBlob = new Blob([files]);//将files对象转为blob对象,第一个参数必须是数组
      console.log(_newBlob);

      //slice()方法 : 切割blob对象,从XX位到XX位
      let _sliceBlob = _newBlob.slice(0,5000);
      console.log(_sliceBlob);

      //将切割后的blob对象转为files对象
      let _sliceFile = new File([_sliceBlob],'test.jpg')
      console.log(_sliceFile);
      
      //fileReader对象 将文件异步方式转为base64格式或文本格式
      // fr.readAsDataURL()  转换为base64格式
      // fr.readAsText()     转换为文本格式
      
      let fr = new FileReader();//实例化FileReader对象
      
      fr.readAsDataURL(_sliceFile)
      // fr.readAsDataURL(files)
      
      //FileReader对象的readAs方法是异步的,只能通过onload事件监听获取转换的结果
      fr.onload = ()=>{
        console.log(fr.result);
        //实现文件上传前的缩略图预览
        this.imgbase64 = fr.result; 
      }
     
    },
};
</script>

      
    },

控制台输出如下:
四次输出顺序分别为切割前的blob对象、切割后的blob对象、转换的files文件对象、读取成base64格式的文件对象
可以看到切割前的blob对象与切割后的blob对象的大小区别,以及文件读取成base64格式后明显不完整
前端批量上传文件,前端,javascript,vue.js

2.3单文件上传

<template>
  <div>
    <p>file组件</p>
    <input type="file" @change="fileChange" multiple>
    <button @click="submit">提交</button>
    <img style="width: 50px;" :src=imgbase64 >
  </div>
 
</template>

<script>

let _fileObj;//定义操作formdata对象实现单文件上传的空变量
export default {
  data(){
    return{
      imgbase64:'',
    }
  },
  methods:{
    fileChange(e){
      let files = e.target.files[0];
      _fileObj = files;
      

      let _newBlob = new Blob([files]);//将files对象转为blob对象,第一个参数必须是数组

      //fileReader对象 将文件异步方式转为base64格式或文本格式
      let fr = new FileReader();
      fr.readAsDataURL(_newBlob);
      
      //通过onload事件监听获取转换的结果,箭头函数赋值给onload,不改变this指向,直接操作data函数中定义的数据
      //文件缩略图操作
      fr.onload = ()=>{
        this.imgbase64 = fr.result
      }
 
    },
    async submit(){
      let _formdata = new FormData();
      
      //append() 将上传者信息或者文件添加到_formdata
      _formdata.append('user','syb');
      _formdata.append('file',_fileObj);
      
	//模拟axios上传请求
      let data = await axios.post('//url',_formdata);
    }
  }
};
</script>

<style scoped>
</style>

2.4多文件上传

将多个文件放到一个数组内,然后循环上传这个数组内的文件对象

如果使用input元素的multiple属性规定可以选择多个文件上传,从用户层面来说并不合适。(因为选择文件的时候要按Ctrl键) 建议使用js拼接input元素获取到的文件对象
<template>
  <div>
    <p>manyFile组件</p>
    <input type="file" @change="fileChange" multiple />
    <button @click="submit">多选提交</button>
    <img style="width: 50px" :src="imgbase64" />
    <span v-for="item in fileList" :key="item.name">{{ item.name }}</span>
    <!-- 使用一个span标签预览要上传的文件名 -->
  </div>
</template>
  

<script>
export default {
  data() {
    return {
      fileList: [],//定义空数组存储多个文件
      imgbase64: "",
    };
  },
  methods: {
    fileChange(e) {
      //e.target.files;//一个由不同文件对象组成的对象
       
      //检测e.target.files是否有多个文件
      if(e.target.files.length > 1){
        console.log(e.target.files);
        this.fileList = [...e.target.files];
        //this.fileList = this.fileList.concat(e.target.files);
      }else{
        this.fileList.push(e.target.files[0])
      }

    },
    async submit() {
		//循环fileList,每次都创建一个formdata对象上传 
        this.fileList.forEach( async item=>{
            let _formdata = new FormData();
            _formdata.append(item.name, item);
            //模拟axios上传请求
      		let data = await axios.post('//url',_formdata);
        })
		
    
    },
  },
};
</script>
  
  
<style scoped>
</style>

2.5切片上传

<template>
    <div>
      <p>sliceFile组件</p>
      <input type="file" @change="fileChange"/>
      <button @click="submit">切片提交</button>
      <div>
        上传进度:{{ precent }}%
      </div>
    </div>
  </template>
    
  
  <script>
  import { test } from "../request/api";
  let _fileObj;
  export default {
    data() {
      return {
        precent: 0,//上传进度百分比
      };
    },
    methods: {
      fileChange(e) {
        _fileObj = e.target.files[0];
      },

      async submit() {
      
        let size = 2*1024*1024; //定义一次切片为2M
        let fileSize = _fileObj.size;
        let current = 0;//定义当前已经上传的文件部分大小
        
        //判断如果已经上传的部分小于文件总大小
        while(current < fileSize){
          let _formData  = new FormData();

		  //一次添加2M大小的切片  注意添加时的说明一般为文件名,后端接收后按照文件名标识拼接
          _formData.append(_fileObj.name,_fileObj.slice(current,current+size))
          let data = await test(_formData);
          //计算当前上传进度,展示到页面
          this.precent = Math.ceil((current/fileSize)*100)
          current += size;
        }
      },
    },
  };
  </script>
    
  <style scoped>
  
  </style>

3、base64格式传输

base64格式可以直接传给后端,后端接收后解码进行相应操作后返回文章来源地址https://www.toymoban.com/news/detail-775866.html

到了这里,关于一次理清前端文件上传操作(单个,多个,大文件切片)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包