vue - 实现文件的上传-文档流下载详细过程
前言
-
上传的时候封装成全局组件,传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通过)
全局上传组件-全局components下
我的命名UploadAnnex/index.vue
<template><el-dialogtitle="合同附件上传":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,},// 合同idid: {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]);// 赋值需要传递文件idthis.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,// 合同iduploadid: 2,updata: "",
父组件回显文件名称和使用结构
<el-form-item label="合同扫描件:" ><el-inputv-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>
父组件事件
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/octet-stream;",});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 - 实现文件的上传-文档流下载详细过程 有了初步的深刻印象,但在实际开发中我 们遇到的情况肯定是不一样的,所以我们要理解它的原理,万变不离其宗。加油,打工人!
什么不足的地方请大家指出谢谢 -- 風过无痕