Vue + WebApi 實(shí)現(xiàn)上傳下載功能(完整示例)
vue上傳:
UI:
<el-button
size="mini"
type="text"
icon="el-icon-document-add"
@click="handleUpload()"
>上傳
</el-button>
<el-dialog
:title="Title"
:visible.sync="open"
width="600px"
append-to-body
:close-on-click-modal="false"
>
<el-upload
ref="upload"
:limit="1"
:on-remove="handleRemove"
:on-error="onError"
:file-list="fileList"
:auto-upload="false"
:http-request="customUpload"
action="http://localhost:5000/api/Resource/AddResource"
class="upload-demo"
>
<el-button slot="trigger" size="small" type="primary"
>選取文件</el-button
>
<el-button
style="margin-left: 10px;"
size="small"
type="success"
@click="submitUpload"
>上傳到服務(wù)器</el-button
>
<div slot="tip" class="el-upload__tip">
支持上傳 {{ strRebuild(fileType) }} 格式,且不超過 {{ fileSize }}M
</div>
</el-upload>
</el-dialog>
點(diǎn)擊按鈕觸發(fā)方法,open為true 上傳彈窗出現(xiàn):
handleUpload() {
this.title = "XXXX";
this.open = true;
},選擇文件后,點(diǎn)擊上傳到服務(wù)器,觸發(fā)以下方法:
customUpload(file) {
console.debug("進(jìn)入上傳方法");
const param = new FormData();
param.append("files", file.file);
console.log("上傳文件:", file);
console.log("FormData:", param);
uploadFile(param);
setTimeout(() => {
this.open = false;
message("success", "上傳成功");
this.$refs.upload.clearFiles();
this.fileList = [];
}, 1500);
},其中觸發(fā)封裝的請(qǐng)求方法:
export async function uploadFile(file) {
try {
console.log("上傳資源參數(shù):", file);
// 嘗試不同的路徑格式
const response = await request.post("/Resource/UploadFile", file);
console.log("API響應(yīng):", response);
return response;
} catch (error) {
console.error("獲取文章列表失敗:", error);
throw error;
}
}.Net 后端Api:
/// <summary>
/// 上傳客戶端文件并保存
/// </summary>
[HttpPost("UploadFile")]
public async Task<IActionResult> UploadFile(IFormFileCollection files)
{
foreach (var file in files)
{
// 判斷文件是否有內(nèi)容
if (file.Length == 0)
{
Console.WriteLine("該文件無任何內(nèi)容!!!");
continue;
}
// 獲取附件原名
string fileName = file.FileName;
// 如果是獲取的含有路徑的文件名,那么截取掉多余的,只剩下文件名和后綴名
if (fileName.Contains("\\"))
{
int index = fileName.LastIndexOf("\\");
fileName = fileName.Substring(index + 1);
}
// 判斷單個(gè)文件大于1M
long fileSize = file.Length;
if (fileSize > 1024 * 1024)
{
Console.WriteLine($"文件大小為(單位字節(jié)):{fileSize}");
Console.WriteLine("該文件大于1M");
}
// 構(gòu)建完整保存路徑
var fullPath = Path.Combine(_webHostEnvironment.WebRootPath, $"Resources/{Guid.NewGuid()}{fileName}");
var directory = Path.Combine(_webHostEnvironment.WebRootPath, $"Resources");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
try
{
// 將文件保存到指定位置
using (var stream = new FileStream(fullPath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return StatusCode(500, new { message = "文件上傳失敗", error = e.Message });
}
}
return Ok(new { success = true, message = "上傳成功" });
}可以使用IFormFileCollection 接口類型對(duì)接前端的FormData類型。通過FileStream 類傳輸文件。
因?yàn)開webHostEnvironment.WebRootPath對(duì)應(yīng)wwwroot,所以文件會(huì)保存在wwwroot目錄下。

其實(shí)應(yīng)該有對(duì)應(yīng)的表格。上傳的文件信息會(huì)保存在數(shù)據(jù)庫里,這里圖方便就沒寫。
下載:
下載的方法有很多種,這里展示Fetch下載:
downloadFile(fileName) {
const fileUrl = this.$baseURL + "\\Resources\\" + fileName; // 文件的URL地址
fetch(fileUrl)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
})
.catch((error) => {
console.error(error);
});
},按鈕調(diào)用:
<button @click="downloadFile('test.png')">下載文件2</button>在方法里直接拼接了圖片(其他文件類似)的url,會(huì)在瀏覽器中下載以下圖片:


完整vue代碼:
<template>
<div class="front-container">
<div>
<h2>往昔崢嶸</h2>
<el-button
size="mini"
type="text"
icon="el-icon-document-add"
@click="handleUpload()"
>上傳
</el-button>
<el-dialog
:title="Title"
:visible.sync="open"
width="600px"
append-to-body
:close-on-click-modal="false"
>
<el-upload
ref="upload"
:limit="1"
:on-remove="handleRemove"
:on-error="onError"
:file-list="fileList"
:auto-upload="false"
:http-request="customUpload"
action="http://localhost:5000/api/Resource/AddResource"
class="upload-demo"
>
<el-button slot="trigger" size="small" type="primary"
>選取文件</el-button
>
<el-button
style="margin-left: 10px;"
size="small"
type="success"
@click="submitUpload"
>上傳到服務(wù)器</el-button
>
<div slot="tip" class="el-upload__tip">
支持上傳 {{ strRebuild(fileType) }} 格式,且不超過 {{ fileSize }}M
</div>
</el-upload>
</el-dialog>
<button @click="downloadFile('test.png')">下載文件2</button>
</div>
<div class="blog-list">
<BlogCard
v-for="blog in blogs"
:key="blog.id"
:blog="blog"
@view-detail="handleViewDetail"
/>
</div>
</div>
</template>
<script>
import { lastSubstring, strRebuildEx } from "@/utils/util";
import { message } from "@/utils/message";
import { blogList } from "../mock/blogData.ts";
import { uploadFile } from "@/api/resources";
import BlogCard from "@/components/BlogCard.vue";
export default {
name: "BlogList",
components: {
BlogCard,
},
data() {
return {
Title: "上傳組件",
open: false,
blogs: blogList,
// 附件列表
fileList: [],
// 允許的文件類型,可依據(jù)實(shí)際需求增加格式
fileType: [
"xls",
"xlsx",
"pdf",
"doc",
"docx",
"txt",
"jpg",
"png",
"jpeg",
"zip",
],
//fileType: ["pdf", "doc", "zip"],
// 運(yùn)行上傳文件大小,單位 M
fileSize: 10,
};
},
methods: {
handleViewDetail(blog) {
console.log("查看博客詳情:", blog);
},
// downloadFile(fileName) {
// const fileUrl = this.$baseURL + "\\Resources\\" + fileName; // 文件的URL地址
// console.debug(fileUrl);
// const link = document.createElement("a");
// link.href = fileUrl;
// link.setAttribute("download", fileName);
// link.click();
// },
downloadFile(fileName) {
const fileUrl = this.$baseURL + "\\Resources\\" + fileName; // 文件的URL地址
fetch(fileUrl)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
})
.catch((error) => {
console.error(error);
});
},
handleUpload() {
this.title = "XXXX";
this.open = true;
},
// 清空表單
clear() {
// 清空附件
this.$refs.upload.clearFiles();
},
// 附件檢查
// 檢查附件是否屬于可上傳類型
// 檢查附件是否超過限制大小
checkFile() {
var flag = true;
var tip = "";
var files = this.$refs.upload.uploadFiles;
files.forEach((item) => {
// 文件過大
if (item.size > this.fileSize * 1024 * 1024) {
flag = false;
tip = " 文件超過" + this.fileSize + "M";
}
// 文件類型不屬于可上傳的類型
if (!this.fileType.includes(lastSubstring(item.name, "."))) {
flag = false;
tip = " 文件類型不可上傳";
this.clientOpen = false;
}
});
if (!flag) {
message("error", tip);
}
return flag;
},
// 提交附件
submitUpload() {
if (this.checkFile()) {
console.log("上傳附件...");
this.$refs.upload.submit();
} else {
console.log("取消上傳");
}
},
// 自定義文件上傳方法
customUpload(file) {
console.debug("進(jìn)入上傳方法");
const param = new FormData();
param.append("files", file.file);
// 模擬上傳成功
console.log("上傳文件:", file);
console.log("FormData:", param);
uploadFile(param);
// 模擬API調(diào)用
setTimeout(() => {
this.open = false;
message("success", "上傳成功");
this.$refs.upload.clearFiles();
this.fileList = [];
}, 1500);
},
// 移除附件
handleRemove(file, fileList) {
console.log("移除附件...");
},
// 附件上傳失敗,打印下失敗原因
onError(err) {
message("error", "附件上傳失敗");
console.log(err);
},
strRebuild(arr) {
strRebuildEx(arr, ",");
},
},
};
</script>
<style>
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #2c3e50;
padding: 1rem 2rem;
}
.nav-brand {
color: white;
font-size: 1.2rem;
font-weight: bold;
}
.nav-links {
display: flex;
align-items: center;
gap: 0;
}
.nav-link {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 4px;
transition: all 0.3s ease;
white-space: nowrap;
}
.nav-link:hover {
background-color: #34495e;
transform: translateY(-1px);
}
.router-link-active {
background-color: #42b883;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.separator {
width: 1px;
height: 20px;
background-color: rgba(255, 255, 255, 0.3);
margin: 0 0.5rem;
}
.el-row {
margin-bottom: 20px;
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.viewmore-row {
float: right;
background: #12b7de;
color: #fff;
border-radius: 3px;
padding: 0px 10px;
height: 30px;
}
.bg-purple {
background: #eaeaea;
-webkit-animation: loading 1s ease-in-out infinite;
animation: loading 1s ease-in-out infinite;
}
@keyframes loading {
0% {
width: 90%;
}
50% {
width: 100%;
}
to {
width: 90%;
}
}
[v-cloak] {
display: none !important;
}
</style>根據(jù)自己需要把其中報(bào)錯(cuò),不相干的代碼刪減掉。
到此這篇關(guān)于Vue + WebApi 實(shí)現(xiàn)上傳下載功能的文章就介紹到這了,更多相關(guān)Vue WebApi上傳下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue動(dòng)態(tài)添加表單的實(shí)現(xiàn)方法
在Vue.js應(yīng)用中,動(dòng)態(tài)表單是一個(gè)常見的需求,尤其是當(dāng)表單字段的數(shù)量和類型需要根據(jù)用戶輸入或系統(tǒng)狀態(tài)動(dòng)態(tài)變化時(shí),本文將詳細(xì)介紹如何在Vue中實(shí)現(xiàn)動(dòng)態(tài)表單的創(chuàng)建,并通過多個(gè)示例展示具體的實(shí)現(xiàn)方法,需要的朋友可以參考下2024-09-09
Vue.js tab實(shí)現(xiàn)選項(xiàng)卡切換
這篇文章主要為大家詳細(xì)介紹了Vue.js組件tab實(shí)現(xiàn)選項(xiàng)卡切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
vue-cli2.x舊版本卸載不掉的問題踩坑指南(附Vue腳手架安裝教程)
遇到一個(gè)Vuecli2腳手架卸載不了的問題,查了許多資料說的都比較復(fù)雜,所以下面這篇文章主要給大家介紹了關(guān)于vue-cli2.x舊版本卸載不掉的問題踩坑的相關(guān)資料,文中還附了Vue腳手架安裝教程,需要的朋友可以參考下2022-07-07
vue結(jié)合leaflet實(shí)現(xiàn)熱力圖
本文主要介紹了vue實(shí)現(xiàn)熱力圖,結(jié)合leaflet.heat插件可以很容易的做出熱力圖,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
vue+element+Java實(shí)現(xiàn)批量刪除功能
這篇文章主要介紹了vue+element+Java實(shí)現(xiàn)批量刪除功能,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
Vue3+TypeScript實(shí)現(xiàn)PDF預(yù)覽組件
這篇文章主要為大家詳細(xì)介紹了如何基于Vue3+TypeScript實(shí)現(xiàn)PDF預(yù)覽組件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04
vue2.0結(jié)合Element實(shí)現(xiàn)select動(dòng)態(tài)控制input禁用實(shí)例
本篇文章主要介紹了vue2.0結(jié)合Element實(shí)現(xiàn)select動(dòng)態(tài)控制input禁用實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05

