文件上传的各个方案及优化(含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>

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

相关推荐
还是鼠鼠21 分钟前
Node.js 包与 npm 详解:使用 npm 的重要注意事项与最佳实践
前端·javascript·vscode·node.js
不能只会打代码2 小时前
六十天前端强化训练之第二十六天之Vue Router 动态路由参数大师级详解
前端·javascript·vue.js·vue router·动态路由参数
不吃香菜的猪2 小时前
vue+echarts实现饼图组件(实现左右联动并且数据量大时可滚动)
前端·javascript·echarts
旺代2 小时前
CSS平面转换
前端·css
難釋懷2 小时前
JavaScript基础-删除事件(解绑事件)
开发语言·前端·javascript
GISer_Jing2 小时前
计算机网络&性能优化相关内容详解
前端·javascript
背藏玫瑰2 小时前
div用contenteditable属性写一个输入框且敏感词显示
开发语言·前端·javascript·敏感词·contenteditable
White graces2 小时前
解决Selenium滑动页面到指定元素,点击失效的问题
java·开发语言·前端·javascript·selenium·测试工具
灵感__idea2 小时前
Vuejs技术内幕:用算法优雅解决复杂问题
前端·vue.js·源码阅读
全宝3 小时前
🐸[保姆级]教你用picgo+github搭建个人图床
前端·github·cdn