前言
-
這個(gè)需求一般是在有合同的地方用,首先不止一個(gè)地方用我們應(yīng)該把他封裝成一個(gè)簡易的全局組件,
-
上傳的時(shí)候封裝成全局組件,傳2個(gè)值,一個(gè)合同id,一個(gè)開關(guān),下載的時(shí)候調(diào)用接口獲取文檔流下載
-
注意看下面的文件上傳下載-細(xì)節(jié)有詳細(xì)的過程和遇到的問題和解決方案
效果圖
接口配置
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',
? //參數(shù)序列化 可加可不加
? paramsSerializer: params => {
? ? return qs.stringify(params)
? },
? //將二進(jìn)制流轉(zhuǎn)換成blob對象
? reponseType: 'blob',
? // 可加可不加
? headers: {
? ? 'Content-Type': 'application/json;charset=UTF-8;'
? }
})
}
文件上傳下載-細(xì)節(jié)
文件上傳時(shí)
1.全局注冊組件-主頁文章有
2.單向數(shù)據(jù)流的問題,要把開關(guān)值通知父組件關(guān)閉使用.sync語法糖,不然會報(bào)錯(cuò)。
3.跟Excel文件上傳是一樣道理,傳遞formdata類型給后端,記得在api二次封裝時(shí)候設(shè)置formdata類型
4.最好在formdata傳2個(gè)值,一個(gè)上傳文件,一個(gè)文件id。方便下載。記得回顯數(shù)據(jù)到父組件輸入框
5.formdatad對象直接打印是空的,要這樣打印 console.log("formdata", formdata.get("file"));
文件下載時(shí)
在網(wǎng)上看來很多文章一頭霧水,自己試一下,在 這里記錄一下。
首先第一點(diǎn)這個(gè)文件下載主要是后端寫,我們只要傳入id即可。但是我們要排查問題。
如果后端把這個(gè)接口寫好了,在測試工具測試可以直接下載,并且返回結(jié)果返回文檔流。那剩下就是前端問題。
代碼是不能直接下載我們需要blob對象轉(zhuǎn)一下,通過a標(biāo)簽來下載。
網(wǎng)上很多文章是說使用windows.URL就可以實(shí)現(xiàn)下載,但是會報(bào)undefined,查閱資料好像是說api廢棄了,我們可以使用webkitURL是一樣效果
還有就是如果我們有全局響應(yīng)攔截的話,可能會過不去。因?yàn)楹蠖丝赡軟]有放回狀態(tài)碼,只有文檔流。那我們就要在request 響應(yīng)攔截加上res != ' '(我們是判斷code通過),axios會默認(rèn)加一層data
如下例子
service.interceptors.response.use(
res => {
// axios默認(rèn)加了一層data
// 這個(gè)res包括這個(gè)請求響應(yīng)回來的所有信息
// 所有的接口請求都會回到這里
// 獲取到本次請求得到的數(shù)據(jù)
const data = res.data
// 會幫所有的請求打印
// console.log(data);
// 判斷本次請求是否成功
if (data.code === 200 || data != '') {
// 如果響應(yīng)成功,則正常給他返回?cái)?shù)據(jù)
return data
} else {
// 證明失敗,我們需要讓外面的catch被調(diào)用
// 要讓catch被調(diào)用,就要手動拋出一個(gè)錯(cuò)誤,并把服務(wù)器返回的消息拋回去
// 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: {
? // 關(guān)閉之前
? handleClose() {
? ? console.log("關(guān)閉之前");
? ? // .sync語法糖,單向數(shù)據(jù)流問題,
? ? // 父組件傳遞給子組件的數(shù)據(jù),子組件直接修改會報(bào)錯(cuò),需要傳遞給父組件修改
? ? this.$emit("update:dialogVisible", false);
? },
? // 輸入款獲取事件
? showimg() {
? ? const that = this;
? ? console.log(that.$refs.file);
? ? console.log(that.$refs.file.files[0]);
? ? // 文件名稱復(fù)制
? ? that.form.contitle = that.$refs.file.files[0].name;
? ? // 聲明一個(gè)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"));
? },
? // 圖標(biāo)觸發(fā)輸入框事件
? changeimg() {
? ? // 點(diǎn)擊圖標(biāo)時(shí)候,觸發(fā)input選擇文件按鈕
? ? this.$refs.file.dispatchEvent(new MouseEvent("click"));
? },
? // 上傳附件
? async addupload() {
? ? // 上傳文文件提示,未選擇文件提示用戶
? ? if (!this.form.contitle) {
? ? ? return this.$message.warning("請先在左側(cè)上傳文件");
? ? }
? ? const res = await uploadPDF(this.formdata);
? ? console.log("合同上傳", res);
? ? // 回顯文件名稱給父組件的form表單
? ? this.$emit("updata", this.form.contitle);
? ? // 清空表單
? ? this.form.contitle = "";
? ? this.formdata = {};
? ? // 關(guān)閉彈框
? ? 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>
父組件數(shù)據(jù)
// 上傳組件開關(guān)
? ? dialogannex: false,
? ? // 合同id
? ? uploadid: 2,
? ? updata: "",
父組件回顯文件名稱和使用結(jié)構(gòu)
<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 是下載文件的名字,可能會因?yàn)榫幋a格式原因中文名字會亂碼。所以可以在這條數(shù)據(jù)文件上傳時(shí)把名字在數(shù)據(jù)庫存一次,查單條的時(shí)候放回來,下載時(shí)候重新賦值名字
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("錯(cuò)誤信息", err);
? ? ? });
? },
總結(jié):
經(jīng)過這一趟流程下來相信你也對 vue - 實(shí)現(xiàn)文件的上傳-文檔流下載詳細(xì)過程 有了初步的深刻印象,但在實(shí)際開發(fā)中我 們遇到的情況肯定是不一樣的,所以我們要理解它的原理,萬變不離其宗。加油,打工人!文章來源:http://www.zghlxwxcb.cn/news/detail-423411.html
什么不足的地方請大家指出謝謝 -- 風(fēng)過無痕文章來源地址http://www.zghlxwxcb.cn/news/detail-423411.html
到了這里,關(guān)于vue - 實(shí)現(xiàn)文件的上傳-文檔流下載詳細(xì)過程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!