文件上传的各个方案及优化(含nodejs后端)

很多人都说文件上传怎么这么难和麻烦,其实文件上传很容易实现,就分为两步。获取文件,然后发送出去。不多逼逼,下面就开始讲述文件上传的各个骚操作

一、文件上传步骤

  1. 获取文件
  2. 发送文件

看上去很简单,但是细分起来还是有很多地方可以讲述的。比如限制文件上传格式,文件上传大小,多文件上传等。

二、文件获取

1.普通获取文件

文件获取的本质就是通过input元素获取。下面的例子全部都用vue3实现。 input元素,设置属性type为file

html 复制代码
<template>
  <div>
    <input type="file"/>
  </div>
</template>

会出现以下的效果

此时选择完文件并且确定后,会触发input元素的change事件,通过event.target.files可以获取到文件列表。因为我们此时只上传了一个文件,所以我们通过event.target.files[0]获取到这个文件。

vue 复制代码
<script setup lang="ts">
import { defineComponent, ref} from "vue";

function fileChange(e: any) {
  const file = e.target.files[0];
  console.log(file);
}
</script>

<template>
  <div>
    <input type="file"/>
  </div>
</template>

我们将会获取到File对象,对象的属性如下

包含最近修改时间、文件名、文件类型、文件大小等属性,file对象其实就是增加了这些额外属性的blob对象,也就是说file对象的原型是blob对象,关于blob(binary large object)对象,不详细讲,可以自行去MDN查询。

2.点击获取文件

只通过input元素获取文件,只能说是丑不拉几。所以我们有了第二种获取文件的方式,本质上也是第一种方式。这种方式非常简单,我们只需要把input元素设置为display:none,并且获取到input元素,增加一个按钮触发input元素的点击事件即可。

vue 复制代码
<script setup lang="ts">
import { defineComponent, ref } from "vue";
//获取到input元素
const inputRef = ref(null);

function fileChange(e: any) {
  const file = e.target.files[0];
  console.log(file);
}

function clickFun() {
    //触发input的点击事件
  inputRef.value.click();
}
</script>

<template>
  <div>
    <input class="hidden" ref="inputRef" type="file" @change="fileChange" />
    <el-button @click="clickFun">选择文件</el-button>
  </div>
</template>

此时我们发现那丑丑的界面就不见了,我们只需要优雅的点击这个按钮就能选择文件了。

3.拖拽获取文件

拖拽获取文件看起来不太简单,但是操作起来还是非常简单的,首先,我们创建一个div,把图片文件拖拽进来,你会发现,文件在浏览器打开了。别慌,这是拖拽的默认行为,我们只需要阻止这个默认行为就行,拖拽会触发很多事件,如dropdragstartdragenddragover

html 复制代码
    <div
      class="w-[100px] h-[100px] bg-slate-600"
      @drop.prevent="handlerDrop"
      @dragover.prevent=""
    >
      DragIn
    </div>

这里我们只需要阻止dropdragover的默认行为就行,只有这两个会打开我们拖拽进来的文件。

我们如何获取这个文件呢,上面也可以看到我们在drop事件绑定了一个函数。 通过drop事件的event.dataTransfer.files可以获取到拖拽进来的文件列表。

js 复制代码
function handlerDrop(event) {
  console.log(event.dataTransfer.files);
}

至此我们已经学会了三种常用的获取文件的方式。

二、上传文件

上传文件就来到了网络请求的部分了,来到网络请求,就得请出我们的老东西Axios。文件上传的时候,有两种常见的表单数据格式,一种是application/x-www-form-urlencodedmultipart/form-data,下面将分别介绍一下

1.application/x-www-form-urlencoded

第一种格式,在这种编码格式下,数据被格式化为键值对,并使用等号(=)连接键和值,不同的键值对之间用与号(&)分隔。空格会被转换为加号(+),特殊字符会被转义为 % 后跟两位十六进制数。用户最终会获得 username=user123&password=pass456这样的格式。以这种方式上传的话我们只能把数据通过base64编码成文本数据传输给服务端。

此时我们需要这样配置axios

js 复制代码
//fileUpload.js
//用于文件上传的请求
import axios from 'axios'

let instance = axios.create()
instance.defaults.baseURL = 'http://127.0.0.1:3000/dev-api/vue-admin-template'
instance.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'

export default instance

代码非常简单只是单纯的配置了Content-Type。接下来我们只需要把file对象转为base64编码的字符串就可以上传文件。

首先我们需要把文件对象转为base64编码的字符串,需要用到fileReader这个类,通过创建的示例中的readAsDataURL,我们可以获取到字符串啦,此时调取axios就可以直接上传了,后端只需要把收到的文件名和文件字符串转为文件保存起来。这样就完成了最简单的上传文件了。

vue 复制代码
<script setup lang="ts">
import { defineComponent, ref, nextTick } from "vue";
import instance from "@/utils/fileUpload";

const base64Url = ref("");

function fileChange(e: any) {
  const file = e.target.files[0];
  
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = async function () {
    base64Url.value = reader.result;
    
    instance({
      url: "upload",
      method: "post",
      data: {
        base64Url: base64Url.value,
        fileName: file.name,
      },
    }).then((res) => {
      console.log(res);
    });
  };
}

const inputRef = ref(null);
function clickFun() {
  inputRef.value.click();
}
</script>

<script lang="ts">
export default defineComponent({
  name: "Index",
});
</script>

<template>
  <div class="m-8">
    <input class="hidden" ref="inputRef" type="file" @change="fileChange" />
    <el-button @click="clickFun">选择文件</el-button>
  </div>
</template>

此刻我们获取到的base64编码还有点妙用,在这也补充一下。

base64URL可以作为img标签的src的属性值我们可以实现图片文件的预览。

vue 复制代码
<script setup lang="ts">
import { defineComponent, ref, nextTick } from "vue";
import instance from "@/utils/fileUpload";
// 文件base64编码格式
const base64Url = ref("");

function fileChange(e: any) {
  const file = e.target.files[0];
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = async function () {
    base64Url.value = reader.result
  };
}

const inputRef = ref(null);

function clickFun() {
  inputRef.value.click();
}
</script>

<template>
  <div class="m-8">
    <input class="hidden" ref="inputRef" type="file" @change="fileChange" />
    <img ref="imageRef" :src="base64Url" />
    <el-button @click="clickFun">选择文件</el-button>
  </div>
</template>

这就是效果图,我们可以直接预览选择的图片。

2.multipart/form-data

第二种方式就是以formdata的格式上传了,这个方式是上传文件最常用也是最简单方法。FormData 适用于包含文件上传等二进制数据的表单。当表单中包含文件上传元素时,可以使用 FormData 来构建请求,因为它支持二进制数据。 首先需要把Content-Type换成multipart/form-data

js 复制代码
//用于文件上传的请求
import axios from 'axios'

let instance = axios.create()

instance.defaults.baseURL = 'http://127.0.0.1:3000/dev-api/vue-admin-template'
instance.defaults.headers['Content-Type'] = 'multipart/form-data'

export default instance

如何构建formData数据呢,需要用到FormData这个对象,通过这个对象能很方便的创建formData格式的数据。此时我们不用将file对象转换为base64编码的文本数据,直接可以上传file对象。

vue 复制代码
<script setup lang="ts">
import { defineComponent, ref, nextTick } from "vue";
import instance from "@/utils/fileUpload";

function fileChange(e: any) {
  const file = e.target.files[0];
  
  const formData = new FormData();
  formData.append("file", file);
  
  instance({
    url: "uploadfile",
    method: "post",
    data: formData,
  }).then((res) => {
    console.log(res);
  });
}

const inputRef = ref(null);

function clickFun() {
  inputRef.value.click();
}
</script>

<template>
  <div class="m-8">
    <input class="hidden" ref="inputRef" type="file" @change="fileChange" />
    <el-button @click="clickFun">选择文件</el-button>
  </div>
</template>

至此我们已经学会了全部上传文件的流程了,剩下的就是切片上传、秒传、断点续传等了

相关推荐
蒜蓉大猩猩13 分钟前
Vue.js - 组件化编程
开发语言·前端·javascript·vue.js·前端框架·ecmascript
王解43 分钟前
一篇文章读懂 Prettier CLI 命令:从基础到进阶 (3)
前端·perttier
乐闻x1 小时前
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前端·vue.js·单元测试
檀越剑指大厂1 小时前
【Python系列】异步 Web 服务器
服务器·前端·python
我是Superman丶1 小时前
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
开发语言·前端·javascript
Hello Dam1 小时前
基于 Spring Boot 实现图片的服务器本地存储及前端回显
服务器·前端·spring boot
小仓桑1 小时前
利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染
前端·javascript·vue.js
Hacker_xingchen1 小时前
Web 学习笔记 - 网络安全
前端·笔记·学习
天海奈奈1 小时前
前端应用界面的展示与优化(记录)
前端
多多*2 小时前
后端并发编程操作简述 Java高并发程序设计 六类并发容器 七种线程池 四种阻塞队列
java·开发语言·前端·数据结构·算法·状态模式