当前位置: 首页 > news >正文

vue+node后台处理大文件切片上传--前端部分

本文主要介绍,在vue3+vite项目下,如何进行有效的大文件上传,本文章主要讲大文件切片上传方式,并提供简单的demo代码供参考

首先,请确保已经创建好项目,这一步跳过。
1、为了选择合适的文件,我们可以先写一个组件,用来选择文件并且将所选择的文件暴露到app.vue中。
下面是我自己写的组件,可以根据自己的需要进行修改操作。主要的部分有,将默认的拖拽事件,比如进入,悬浮,离开全部阻止默认行为,只允许放置操作,并且在放置操作完成文件内容的读取,代码如下:
FileUpload.vue

<template><div><div class="upload-demo" ref="up"><el-icon class="el-icon--upload"><upload-filled /></el-icon></div></div>
</template><script setup name="FileUpload">
import { UploadFilled } from '@element-plus/icons-vue'
import { onMounted, reactive, ref } from 'vue'const up = ref(null);
const fileUrl = reactive({});
const emit = defineEmits(['getFile']);
onMounted(() => {console.log(up.value)up.value.addEventListener('dragenter', (e)=>{ //阻止默认事件e.preventDefault();e.stopPropagation();})up.value.addEventListener('dragover', (e)=>{e.preventDefault();e.stopPropagation();})up.value.addEventListener('dragleave', (e)=>{e.preventDefault();e.stopPropagation();})up.value.addEventListener('drop', async (e)=>{e.preventDefault();e.stopPropagation();const f = e.dataTransfer.files;  //在此处获取用户拖拽进去组件的文件数组const file = f[0];   //取第一个,在这里我默认只拖拽一个,可以自己选择性进行扩展,如果怕f为空报错,选择trycatch,我为了方便就没写if(!file) return console.error('没有文件')if(file.size > 1024*1024*1024*2) return console.error('文件太大'); //文件超过2G,太大不上传if(!file.type.startsWith('video')) return console.error('只能上传视频文件'); Object.assign(fileUrl, file) emit('getFile', file);})
})
defineExpose({fileUrl})
</script><style scoped>
.upload-demo{width: 200px;height: 100px;border: 1px dotted gray;transition: all 3s;font-size: 100px;display: flex;justify-content: center;align-items: center;
}
.upload-demo:hover{border: 1px dotted blue
}
</style>

在app.vue中引用组件:

<FileUpload @getFile="getFile"></FileUpload>

其中涉及到的getfile方法,为子组件调用函数触发的方法,主要用来传递选中的文件:

let url = ref('');
let upfile = reactive<{[key: string]: string}>({});
let appfile:any = null;
function getFile(file:any){console.log('child set:', file);console.log(typeof file);  //File类型,根据原型链,底层是objectif(typeof file != 'object'){return console.error('文件格式不对,非对象');}url.value = URL.createObjectURL(file);  //创建临时URL地址,索引到用户本地的文件地址,方便页面展示appfile = file;console.log(appfile);Object.assign(upfile, {  //创建一个包含文件地址,文件名,类型的对象进行保存url,type: file.type,name: file.name})
}

子组件到这里就结束,我将主体逻辑写到app中,方便展示,最好的方式还是全部封装到子组件,达到高内聚低耦合,每一个模块只干一件事。
2、获取唯一的文件名称
通常,对于每一个相同的文件,我们需要为其生成一个唯一的名字,然后上传到服务器,根据唯一名称,判断是否同一个文件,节省资源的同时,提高用户体验。如何根据文件内容获取唯一的文件名称,我们先将文件内容转为二进制,再利用浏览器提高的api:crypto.subtle.digest生成哈希值(注意,该方法异步,容易被忽略),再转为16进制字符串,这就是文件的唯一名:

async function getFilename(){const hashname = await getFileHashname();const fileExtension = upfile.name.split('.').pop();return `${hashname}.${fileExtension}`;
}
async function getFileHashname(){console.log(appfile);const arrayBuffer = await appfile.arrayBuffer();const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);const hex = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');return hex;
}

3、切片操作
首先认识一下文件大小的概念,浓缩为以下公式:
1GB = 1024MB = 1024*1024KB = 1024*1024*1024B
那么文件切片,也就是将很大的文件切成很多块,每块的大小我们自己决定,当然,在现实应用中,是需要根据网络流量,服务器的负载等因素进行动态调整这个切片的大小,我们切片的过程中,完全可以把File当成一个具有一定大小的数组,如果你这么思考,那么下面的代码将通俗易懂,主要做的就是存储切后的块,此外,我们还需要将切片的顺序写入切片名字中,后端可以识别然后进行拼接。

//切片操作 切成10*1024*1024,也就是10MB
const CHUNKS_SIZE = 10 * 1024 * 1024;
async function sectionFile(filename:string){console.log(filename);const chunks = createChunks(filename);console.log(chunks);return chunks;
}
function createChunks(filename: string){let chunks = [];const count = Math.ceil(appfile.size / CHUNKS_SIZE);for(let i = 0; i < count; i++){let chunk = appfile.slice(i*CHUNKS_SIZE, (i+1)*CHUNKS_SIZE);chunks.push({chunk,chunkFileName: `${filename}-${i}`})}return chunks;
} 

3、封装axios
这一步主要做的操作是提前封装一下axios,更加好的适应后端返回的主体内容,当然,你可以选择不进行这一步,因为这不是必须的。
简单封装axios,判断是否返回的主体内容有success,否则抛出错误。

import axios from 'axios';const axiosInstance = axios.create({baseURL: 'http://localhost:8080'
})
axiosInstance.interceptors.response.use((response)=>{ if(response.data && response.data.success){return response.data;} else {return new Error(response.data.msssage || 'service error')}},(error)=>{console.log(error);return error;
})

4、上传进度条
一开始小伙伴肯定很好奇,为什么我发送的请求看不见进度,但是别人怎么看见进度的,难道后端有返回参数嘛,当然不是!如果要一直返回参数,那这个开销可就不得了啦! 其实事情是这样子的,axios请求提供一个方法,来监听上传的进度,也就是请求的进度,如果你能够熟练使用这个方法,那么对页面的一些交互大有裨益!这个方法就是onUploadProgress! 其中参数是progressEvent,有两个重要属性,total和loaded,意义如同属性名:但是值得注意的是:loaded是一个0~1的范围数据,所以下面的代码有细节,请注意哦,如果你发现这个小小小的细节,请在评论区打出!~

let progress = reactive<{[key: string]: number}>({});
onUploadProgress: (progressEvent)=>{if(!progressEvent.total) return ;const percentProgress = Math.round(progressEvent.loaded*100 / progressEvent.total)Object.assign(progress, {...progress, [item.chunkFileName]: percentProgress})console.log("shangchuangzhong");}

5、上传文件
到这里,就差最重要的上传文件啦~先来一个按钮,:

 <button @click="uploadFile">上传</button><el-progress v-for="(item, index) in getpro" :percentage="item" :key="index"/>

所谓文件切片,其实最重要的就是实现文件切片后,可以将切片并行上传,可以极大加快上传的效率,因为充分利用了服务器的吞吐量和效率。所以上述我们已经完成切片,而且将切片的顺序写入切片名字中,后端可以识别然后进行拼接,所以在上传完切片后,还需要发送一个合并文件的请求:

async function uploadFile(){const filename = await getFilename();console.log('name: ', filename);const chunks = await sectionFile(filename);const requsetList = chunks.map(item => {return axiosInstance.post(`/upload/${filename}`, item.chunk, {headers:{'Content-Type':'application/octet-stream'},params: {chunkFileName: item.chunkFileName},onUploadProgress: (progressEvent)=>{if(!progressEvent.total) return ;const percentProgress = Math.round(progressEvent.loaded*100 / progressEvent.total)Object.assign(progress, {...progress, [item.chunkFileName]: percentProgress})console.log("shangchuangzhong");}})})try {await Promise.all(requsetList);//切片发送完还需要发一个合并文件内容的请求await axiosInstance.get(`/mergeFile/${filename}`, {headers: {'Content-Type': 'application/json'}}).then(()=>{console.log('rollback');// Object.assign(progress, null) //没法做到清空对象Object.keys(progress).forEach(key => {delete progress[key];});})console.log('上传完毕!')} catch (error) {console.log(error);return ;}
}

到这里就ok啦!

相关文章:

vue+node后台处理大文件切片上传--前端部分

本文主要介绍&#xff0c;在vue3vite项目下&#xff0c;如何进行有效的大文件上传&#xff0c;本文章主要讲大文件切片上传方式&#xff0c;并提供简单的demo代码供参考 首先&#xff0c;请确保已经创建好项目&#xff0c;这一步跳过。 1、为了选择合适的文件&#xff0c;我们…...

【通俗理解】艺术与数学交融

【通俗理解】艺术与数学交融 艺术与数学的奇妙交融 你可以把艺术比作一个“梦幻花园”&#xff0c;它充满了无限的可能性和美感。而数学则是一把“精密钥匙”&#xff0c;它能够解开花园中的秘密&#xff0c;揭示美的内在结构。 艺术与数学交融的核心作用 组件/步骤描述艺术表…...

深入探讨 Docker 容器文件系统

引言 随着云计算和微服务架构的兴起&#xff0c;Docker 容器技术迅速成为开发和运维人员的首选工具。Docker 容器不仅提供了一种轻量级的虚拟化方式&#xff0c;还简化了应用程序的部署和管理。在众多的技术细节中&#xff0c;Docker 容器文件系统是一个至关重要的组成部分。本…...

《LeetCode热题100》---<4.子串篇三道>

本篇博客讲解LeetCode热题100道子串篇中的三道题 第一道&#xff1a;和为 K 的子数组 第二道&#xff1a;滑动窗口最大值 第三道&#xff1a;最小覆盖子串 第一道&#xff1a;和为 K 的子数组&#xff08;中等&#xff09; 法一&#xff1a;暴力枚举 class Solution {public in…...

全国区块链职业技能大赛样题第9套前端源码

后端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746050 前端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746216 智能合约+数据库表设计:https://blog.csdn.net/Qhx20040819/article/details/140746646 登录 ​ 用户管理...

如何提高编程面试成功率:LeetCode Top 100 问题及解答解析(详细面试宝典)

以下是 LeetCode Top 100 面试必备题目及其解决方案示例。这些题目涵盖了数据结构、算法、动态规划、回溯等多种重要的面试话题。希望各位同学有所收货&#xff0c;早日脱离底层到达彼岸&#xff01; 1. Two Sum 题目: 给定一个整数数组 nums 和一个目标值 target&#xff0c…...

K-近邻和神经网络

K-近邻&#xff08;K-NN, K-Nearest Neighbors&#xff09; 原理 K-近邻&#xff08;K-NN&#xff09;是一种非参数分类和回归算法。K-NN 的主要思想是根据距离度量&#xff08;如欧氏距离&#xff09;找到训练数据集中与待预测样本最近的 K 个样本&#xff0c;并根据这 K 个…...

用EasyV全景图低成本重现真实场景,360°感受数字孪生

全景图&#xff0c;即借助绘画、相片、视频、三维模型等形式&#xff0c;通过广角的表现手段&#xff0c;尽可能多表现出周围的环境。避免了一般平面效果图视角单一&#xff0c;不能带来全方位视角的缺陷&#xff0c;能够全方位的展示360度球型范围内的所有景致&#xff0c;最大…...

【Golang 面试 - 进阶题】每日 3 题(九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…...

孟德尔随机化、R语言,报错,如何解决?

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…...

一文剖析高可用向量数据库的本质

面对因电力故障、网络问题或人为操作失误等导致的服务中断&#xff0c;数据库系统高可用能够保证系统在这些情况下仍然不间断地提供服务。如果数据库系统不具备高可用性&#xff0c;那么系统就需要承担停机和数据丢失等重大风险&#xff0c;而这些风险极有可能造成用户流失&…...

JavaScript青少年简明教程:异常处理

JavaScript青少年简明教程&#xff1a;异常处理 在 JavaScript 中&#xff0c;异常指的是程序执行过程中出现的错误或异常情况。这些错误可能导致程序无法正常执行&#xff0c;甚至崩溃。ECMA-262规范了多种JavaScript错误类型&#xff0c;这些类型都继承自Error基类。主要的错…...

科普文:Lombok使用及工作原理详解

1. 概叙 Lombok是什么&#xff1f; Project Lombok 是一个 JAVA 库&#xff0c;它可以自动插入编辑器和构建工具&#xff0c;为您的 JAVA 锦上添花。再也不要写另一个 getter/setter 或 equals 等方法&#xff0c;只要有一个注注解&#xff0c;你的类就有一个功能齐全的生成器…...

飞致云开源社区月度动态报告(2024年7月)

自2023年6月起&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大屏…...

mybatis-plus——实现动态字段排序,根据实体获取字段映射数据库的具体字段

前言 前端需要根据表头的点击控件可以排序&#xff0c;虽然前端能根据当前页的数据进行对应字段的排序&#xff0c;但也仅局限于实现当前页的排序&#xff0c;无法满足全部数据的排序&#xff0c;所以需要走接口的查询进行排序&#xff0c;获取最全的排序数据 实现方案 前端…...

redis:Linux安装redis,redis常用的数据类型及相关命令

1. 什么是NoSQL nosql[not only sql]不仅仅是sql。所有非关系型数据库的统称。除去关系型数据库之外的都是非关系数据库。 1.1为什么使用NoSQL ​ NoSQL数据库相较于传统关系型数据库具有灵活性、可扩展性和高性能等优势&#xff0c;适合处理非结构化和半结构化数据&#xff0c…...

JavaScript 和 HTML5 Canvas实现图像绘制与处理

前言 JavaScript 和 HTML5 的 canvas 元素提供了强大的图形和图像处理功能&#xff0c;使得开发者能够在网页上创建动态和交互式的视觉体验。这里我们将探讨如何使用 canvas 和 JavaScript 来处理图像加载&#xff0c;并在其上进行图像绘制。我们将实现一个简单的示例&#xf…...

Java之Java基础二十(集合[上])

Java 集合框架可以分为两条大的支线&#xff1a; ①、Collection&#xff0c;主要由 List、Set、Queue 组成&#xff1a; List 代表有序、可重复的集合&#xff0c;典型代表就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList&#xff1b;Set 代表无序、不可重复的集…...

【C++BFS】1162. 地图分析

本文涉及知识点 CBFS算法 LeetCode1162. 地图分析 你现在手里有一份大小为 n x n 的 网格 grid&#xff0c;上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋&#xff0c;1 代表陆地。 请你找出一个海洋单元格&#xff0c;这个海洋单元格到离它最近的陆地单元格的距…...

实战:安装ElasticSearch 和常用操作命令

概叙 科普文&#xff1a;深入理解ElasticSearch体系结构-CSDN博客 Elasticsearch各版本比较 ElasticSearch 单点安装 1 创建普通用户 #1 创建普通用户名&#xff0c;密码 [roothlink1 lyz]# useradd lyz [roothlink1 lyz]# passwd lyz#2 然后 关闭xshell 重新登录 ip 地址…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...