【前端】-【前端文件操作与文件上传】-【前端接受后端传输文件指南】

目录

前端文件操作与文件上传

一、前端文件上传有两种思路:

  1. 二进制blob传输:典型案例是formData传输,相当于用formData搭载二进制的blob传给后端
  2. base64传输:转为base64传输,后端再将base64转回来。简便、耗时

二、与文件相关的对象

  1. files:通过input标签读过来的文件对象,是blob的子类。
  2. blob:不可变的二进制内容,包含很多操作方法,切片上传、断点续传都是基于blob的
  3. formData:用于后端传输的对象。files是一个前端的对象,不能直接传给后端,所以我们需要一个前后端都认可的载体来传递文件,这个载体就是formData。formData就像一辆汽车用来搭载files,这样才能让文件以二进制的形式传到后端
  4. fileReader:多用于把文件读取为某种形式(如base64、text文件)直接传给后端

三、file参数、blob切割文件、FileReader将文件转成base64,浓缩图/文本预览:

html 复制代码
<template>
  <div>
    <input type="file" name="file" @change="fileChange" />
    <!-- 缩略图,文本预览 -->
    <img style="width:200px;" :src="imgbase64" />
    <button @click="submit">提交</button>
  </div>
</template>

<script>
import axios from "axios"
import { fstat } from "fs";
let _fileObj;
export default {
  name: 'HelloWorld',
  data() {
    return {
      imgbase64: "",
    }
  },
  methods: {
    fileChange(e) {
       let file = e.target.files[0]// files是个数组
       _fileObj = file;
       // file常用属性:size(大小)、type(类型)、name(文件名)
      if (file.size > 10 * 24 * 24) {
        alert("文件不能大于十兆")
      }
      if (file.type !== 'video/mp4') {
        alert("必须是mp4")
      }
      // 使用blob的slice方法可以切割文件
      let _sliceBlob = new Blob([file]).slice(0, 5000);// 切割二进制的0-5000位
      // 将切割后的Blob对象转成File对象(第二个参数是文件名),之后就可以上传切割后的File对象
      let _sliceFile = new File([_sliceBlob], "test.png");
      
      //将File对象或者Blob对象转成base64或text
      let fr = new FileReader();
      fr.readAsDataURL(_sliceFile);// readAsDataURL是转成base64的方法
      let self = this;
      fr.onload = function () {
        // base64是异步的转换,通过onload方法获得转换结果
        self.imgbase64 = fr.result// 直接将转换结果赋值给img的src,设置src的大小即可获得浓缩图
        console.log(fr.result)// 打印结果见下图一
      }
    },
    async submit() {
    // 这部分的代码后面讲
    	let _formData = new FormData();
        _formData.append("user", "asdasd");
        _formData.append("file", _fileObj)
        axios.post("/xx", _formData);
    }
    }
  }
}
</script>

四、formData:不仅可以搭载文件,还可以搭载文字、input的其他输入

html 复制代码
<form action="xxx" method="post">默认情况下提交为query参数</from>
<form action="xxx" method="post" enctype="multipart/form-data">enctype指定提交为formData</from>

五、文件上传:将blob转成FormData上传

javascript 复制代码
async submit() {
	let _formData = new FormData();
    _formData.append("user", "asdasd");
    _formData.append("file", _fileObj)
    axios.post("/xx", _formData);
}

通过查看网络可以发现:

  1. 上传内容:
  2. 请求头content-Type指定了传输内容为form-data,且boundary指定了分割符
  3. 分隔了两个内容(下面还有一个分割线,即以分割线结尾)

    六、转换关系
  4. 我们直接拿到的是file对象,file对象可以转换成Blob对象,Blob对象也可以转成file对象
  5. file、blob都可以根据FileReader读成base64或text文本
  6. 通过接口传输给后端时,只能传输base64、text文本、formData,所以,如果不把file、blob通过FileReader读成base64或text文本,那么就需要把file或者blob append到formData才能通过接口传输

七、具体功能

  1. 单文件上传(详见前述代码)
  2. 多文件上传:
html 复制代码
<template>
  <div>
    <input type="file" name="file" @change="fileChange" multiple />
    <span v-for="item in imgList">{{ item.name }}</span>
    <button @click="submit">提交</button>
  </div>
</template>

<script>
import axios from "axios"
import { fstat } from "fs";
let _fileObj;
export default {
  name: 'HelloWorld',
  data() {
    return {
      imgList: [],
    }
  },
  methods: {
    fileChange(e) {
      //多文件上传
      // multiple的多文件上传其实很不友好,需要用户在选择文件时按住ctrl多选,否则就会变成单选
      // 所以使用imgList数组将用户每次选择的内容都push进去
      if (e.target.files.length > 1) {
        
        this.imgList.concat(e.target.files)
      } else {
        this.imgList.push(e.target.files[0]);
      }
      //切片上传
      _fileObj = e.target.files[0]
    },
    async submit() {
      // 遍历,一个一个上传
      this.imgList.forEach((item) => {
        let _formData = new FormData();
        _formData.append(item.name + "file", item)
        axios.post("/xx", _formData);
      })
    }
  }
}
</script>
  1. 切片上传
html 复制代码
<template>
  <div>

    <input type="file" name="file" @change="fileChange" multiple />
    <div>{{ precent }}%</div>
    <button @click="submit">提交</button>
  </div>
</template>

<script>
import axios from "axios"
import { fstat } from "fs";
let _fileObj;
export default {
  name: 'HelloWorld',
  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;// 当前已经传了多少
      // 断点续传,永久记录中断的地方,下次上传时直接从断点开始传
      //localStorage.setItem(_fileObj.name, current);
      while (current < fileSize) {
        let _formData = new FormData();
        _formData.append(_fileObj.name, _fileObj.slice(current, current + size))
        await axios.post("http://localhost:4000/upload",_formData)
        // 进度条可以用axios的onUploadProgress方法,且发送切片时可以并行发送请求,后续可以自行优化
        this.precent = Math.min((current / fileSize) * 100, 100)
        current += size;
      }
    }
  }
}
</script>

File System Access API 允许直接读取、写入或保存对用户设备上的文件和文件夹的更改。从 Chrome 86 开始支持 File System Access API,目前只有基于 Chromium 系列的浏览器全面支持,Safari 部分支持(支持读取,不支持写入和保存),而 Firefox 未支持。

前端接受后端传输文件指南

相关推荐
天蓝色的鱼鱼19 分钟前
都2026年了还不会Vite插件开发?手写一个版本管理插件,5分钟包会!
前端·vite
苏武难飞31 分钟前
分享一个33号远征队的效果!
前端
鹏程十八少1 小时前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
亿元程序员1 小时前
这款值68亿的游戏,你不实战一下吗?安排!
前端
摸鱼的春哥2 小时前
Agent教程15:认识LangChain(中),状态机思维
前端·javascript·后端
明月_清风2 小时前
告别遮挡:用 scroll-padding 实现优雅的锚点跳转
前端·javascript
明月_清风2 小时前
原生 JS 侧边栏缩放:从 DOM 监听到底层优化
前端·javascript
万少11 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站13 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名15 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员