首页 > 其他分享 >vue - 实现文件的上传-字节流下载详细过程

vue - 实现文件的上传-字节流下载详细过程

时间:2023-10-26 09:22:56浏览次数:33  
标签:文件 vue 字节 上传 formdata 组件 data id

前言
这个需求一般是在有合同的地方用,首先不止一个地方用我们应该把他封装成一个简易的全局组件,

上传的时候封装成全局组件,传2个值,一个合同id,一个开关,下载的时候调用接口获取文档流下载

注意看下面的文件上传下载-细节有详细的过程和遇到的问题和解决方案

效果图
接口配置
import request from '@/utils/request'

// 上传合同附件
export function uploadPDF (data) {
return request({
url: '/contractMsg/updatePDF',
method: 'put',
headers: { 'Content-Type': 'multipart/form-data' },
data
})
}

// 下载合同附件
export function download (id) {
return request({
url: `/contractMsg/getPDF/${id}`,
method: 'get',
//参数序列化 可加可不加
paramsSerializer: params => {
return qs.stringify(params)
},
//将二进制流转换成blob对象
reponseType: 'blob',
// 可加可不加
headers: {
'Content-Type': 'application/json;charset=UTF-8;'
}
})
}

文件上传下载-细节
文件上传时

1.全局注册组件-主页文章有

2.单向数据流的问题,要把开关值通知父组件关闭使用.sync语法糖,不然会报错。

3.跟Excel文件上传是一样道理,传递formdata类型给后端,记得在api二次封装时候设置formdata类型

4.最好在formdata传2个值,一个上传文件,一个文件id。方便下载。记得回显数据到父组件输入框

5.formdatad对象直接打印是空的,要这样打印 console.log("formdata", formdata.get("file"));

文件下载时

在网上看来很多文章一头雾水,自己试一下,在 这里记录一下。

首先第一点这个文件下载主要是后端写,我们只要传入id即可。但是我们要排查问题。

如果后端把这个接口写好了,在测试工具测试可以直接下载,并且返回结果返回文档流。那剩下就是前端问题。

代码是不能直接下载我们需要blob对象转一下,通过a标签来下载。

网上很多文章是说使用windows.URL就可以实现下载,但是会报undefined,查阅资料好像是说api废弃了,我们可以使用webkitURL是一样效果

还有就是如果我们有全局响应拦截的话,可能会过不去。因为后端可能没有放回状态码,只有文档流。那我们就要在request 响应拦截加上res != ' '(我们是判断code通过),axios会默认加一层data

如下例子

service.interceptors.response.use(
res => {
// axios默认加了一层data
// 这个res包括这个请求响应回来的所有信息
// 所有的接口请求都会回到这里
// 获取到本次请求得到的数据
const data = res.data
// 会帮所有的请求打印
// console.log(data);
// 判断本次请求是否成功
if (data.code === 200 || data != '') {
// 如果响应成功,则正常给他返回数据
return data
} else {
// 证明失败,我们需要让外面的catch被调用
// 要让catch被调用,就要手动抛出一个错误,并把服务器返回的消息抛回去
// Message.warning(data.message)
return Promise.reject(data.message)
}
},
}

全局上传组件-全局components下

我的命名UploadAnnex/index.vue

<template>
<el-dialog
title="合同附件上传"
:visible.sync="dialogVisible"
width="40%"
:before-close="handleClose"
>
<el-form ref="form" :model="form" size="small" label-width="80px">
<el-form-item label="文件名称:">
<el-input v-model="form.contitle"></el-input>
</el-form-item>
<el-form-item label="文件上传:">
<div class="uppicture">
<input type="file" class="upinput" ref="file" @change="showimg" />
<i class="el-icon-plus" id="changes" @click="changeimg"></i>
<p>上传合同文件附件</p>
<el-button type="primary" class="uploadbutton" @click="addupload"
>上传附件{{ id }}</el-button
>
</div>
</el-form-item>
</el-form>

<span slot="footer" class="dialog-footer">
<el-button @click="handleClose" style="background: #f7f7f7" size="small"
>取 消</el-button
>
<!-- <el-button type="primary" @click="upload">确 定</el-button> -->
</span>
</el-dialog>
</template>

<script>
import { uploadPDF } from "@/api/client/administrator";
export default {
name: "UploadAnnex",
data() {
return {
form: {
// 合同名称
contitle: "",
},
formdata: {},
};
},
props: {
// 显示隐藏
dialogVisible: {
type: Boolean,
// 必传
required: true,
},
// 合同id
id: {
type: Number,
// 必传
required: true,
},
},
methods: {
// 关闭之前
handleClose() {
console.log("关闭之前");
// .sync语法糖,单向数据流问题,
// 父组件传递给子组件的数据,子组件直接修改会报错,需要传递给父组件修改
this.$emit("update:dialogVisible", false);
},
// 输入款获取事件
showimg() {
const that = this;
console.log(that.$refs.file);
console.log(that.$refs.file.files[0]);
// 文件名称复制
that.form.contitle = that.$refs.file.files[0].name;
// 声明一个formdata对象
this.formdata = new FormData();
// 赋值需要传递的文件-添加到formdata对象中
this.formdata.append("file", that.$refs.file.files[0]);
// 赋值需要传递文件id
this.formdata.append("id", this.id);
// 打印formdata对象
console.log("formdata", formdata.get("file"));
},
// 图标触发输入框事件
changeimg() {
// 点击图标时候,触发input选择文件按钮
this.$refs.file.dispatchEvent(new MouseEvent("click"));
},
// 上传附件
async addupload() {
// 上传文文件提示,未选择文件提示用户
if (!this.form.contitle) {
return this.$message.warning("请先在左侧上传文件");
}
const res = await uploadPDF(this.formdata);
console.log("合同上传", res);
// 回显文件名称给父组件的form表单
this.$emit("updata", this.form.contitle);
// 清空表单
this.form.contitle = "";
this.formdata = {};
// 关闭弹框
this.handleClose();
},
},
};
</script>

<style lang="scss" scoped>
::v-deep .el-dialog {
border-radius: 10px;
.el-dialog__header {
border-radius: 9px 9px 0 0;
background-color: #1488c6;
padding: 8px 20px;
.el-dialog__title {
color: white;
font-size: 16px;
}

.el-dialog__headerbtn {
top: 12px;
i {
color: white;
}
}
}
.el-dialog__footer {
text-align: center;
}
.el-dialog__body {
padding: 12px;
}
.uppicture {
width: 120px;
height: 120px;
border: 1px solid #717376;
position: relative;
cursor: pointer;
input {
width: 100%;
height: 100%;
vertical-align: middle;
opacity: 0;
}
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 30px;
// background-color: skyblue;
}
p {
position: absolute;
bottom: -2px;
left: 50%;
word-break: keep-all;
transform: translate(-50%);
}
.uploadbutton {
position: absolute;
bottom: 0;
margin-left: 20px;
}
&:hover {
color: #2da9fa;
border: 1px solid #2da9fa;
p {
color: #2da9fa;
}
}
}
}
</style>

使用组件-父组件
<!-- 上传组件使用 -->
<UploadAnnex
:dialogVisible.sync="dialogannex"
:id="uploadid"
@updata="updata = $event"
></UploadAnnex>
父组件数据

// 上传组件开关
dialogannex: false,
// 合同id
uploadid: 2,
updata: "",
父组件回显文件名称和使用结构

<el-form-item label="合同扫描件:" >
<el-input
v-model="updata"
style="width: 350px; margin-right: 10px"
></el-input>
<el-button @click="download">下载</el-button>
<el-button @click="addupload">上载</el-button>
</el-form-item>
父组件事件

link.download 是下载文件的名字,可能会因为编码格式原因中文名字会乱码。所以可以在这条数据文件上传时把名字在数据库存一次,查单条的时候放回来,下载时候重新赋值名字

import { download } from "@/api/client/administrator";

// 上传组件按钮
addupload() {
this.dialogannex = true;
},
// 下载文件
async download() {
await download(this.uploadid)
.then((res) => {
console.log("res", res);
let blob = new Blob([res.data], {
type: "application/pdf;",
});
console.log("blob", blob);
let filename = "css.doc";
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement("a");
link.href = webkitURL.createObjectURL(blob);
link.download = filename;
link.click();
webkitURL.revokeObjectURL(link.href);
}
})
.catch((err) => {
console.log("错误信息", err);
});
},

总结:

经过这一趟流程下来相信你也对 vue - 实现文件的上传-文档流下载详细过程 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!

 

参考文章:http://blog.ncmem.com/wordpress/2023/10/26/vue-%e5%ae%9e%e7%8e%b0%e6%96%87%e4%bb%b6%e7%9a%84%e4%b8%8a%e4%bc%a0-%e5%ad%97%e8%8a%82%e6%b5%81%e4%b8%8b%e8%bd%bd%e8%af%a6%e7%bb%86%e8%bf%87%e7%a8%8b/

欢迎入群一起讨论

 

 

标签:文件,vue,字节,上传,formdata,组件,data,id
From: https://www.cnblogs.com/songsu/p/17788650.html

相关文章

  • vue和element ui 滑块组件 重置验证滑块父组件ref调用子组件函数,子组件调用自己dom标
    css3可以改变图片的颜色了。从此再也不用设计出多张图,而且随时可以修改。下面就简单介绍下css3中是如何做到改变背景图片的颜色效果的。方式一:利用css3滤镜filter中的drop-shadow代码如下:<style>.icon{display:inline-block;width:180px;height:180px;bac......
  • Vue绑定Style和Class写法
    vue2写法<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width,initial-scale=1.0"/><title>......
  • Java基础 打印流、字节打印流
      打印流是高级流,也是用来包装基本流的但是打印流不能读,只能写,所以打印流只有输出流 打印流分为两种:PrintStream、PrintWriter两个类1.PrintStream  →  字节打印流2.PrintWriter  →  字符打印流 打印流的特点:1.打印流只能操作文件目的地,不能操作......
  • Java拾贝第十一天——IO流之字节流复制图片、视频
    Java拾贝不建议作为0基础学习,都是本人想到什么写什么文件在硬盘或传输时都以字节的形式进行传输。包括图片、视频等。思路:先定位源文件file1作为源文件,file2作为复制文件使用字节流输入流读取file1使用字节流输出流输出file2关闭流。定位源文件,我特地翻出来一张学校......
  • python的requests发送/上传多个文件(转)
    原文:https://blog.csdn.net/five3/article/details/74913742作者:上帝De助手 1、需要的环境Python3.XRequests库2、单字段发送单个文件在requests中发送文件的接口只有一种,那就是使用requests.post的files参数,请求形式如下:url="http://httpbin.org/post"data=No......
  • vue的通讯方式
    vue中通讯方式propsemitv-modelrefsprovide/injecteventBusVuex/pinia(vue3)1.Props方式父组件以数据绑定的形式声明要传递的数据,子组件通过defineProperty()方法创建props对象,即可拿到父组件传来的数据,该方式用于父传子。 父组件的template中:<!--list是我们要......
  • Vue:watch的多种使用方法
    好家伙, 补了一下watch的多种用法 1.属性:方法(最常用)使用最广泛的方式是将watch选项设置为一个对象,对象的属性是要观测的数据属性,值是一个回调函数,该回调函数会在属性变化时触发。例如:watch:{firstName:function(newVal,oldVal){console.log('firstNamec......
  • 配置第一个vue项目
    基础环境准备参考:https://www.cnblogs.com/lelexiong/p/17787970.html1、打开vscode终端,配置脚手架vue-clinpminstall-gvue-cli2、安装webpack,它是打包js的工具npminstall-gwebpack3、vscode打开所创建的空文件夹,执行命令创建项目vueinitwebpackvue-demo4......
  • vue el-select 下拉菜单 数据回显不在清除数据可编辑状态
    思路:当点击options的时候,让select失去焦点(跳到其他的地方),添加el-input就是为了把光标跳转到其上面,然后将其隐藏掉,则为看不到光标点,但是在点击第一次之后获取焦点focus之后,隐藏掉下拉菜单的时候@blur是无效的,此时只能通过监听下拉框是否是隐藏和显示状态来让其失去焦点事件,所以......
  • 使用 content scripts 和 Vue Router 等技术在当前页面中注入和显示 Vue 单文件组件
    要在当前页面中注入和显示Vue单文件组件,您需要按照以下步骤操作:创建一个Vue项目:首先,确保您有一个Vue项目,包括您的Vue单文件组件以及相应的构建配置。将构建后的文件添加到插件目录:将Vue项目构建后生成的HTML、CSS和JavaScript文件添加到您的Chrome插件的目录中。编......