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

Vue + WebApi 实现上传下载功能

vue上传:

UI:

  <el-buttonsize="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-uploadref="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-buttonstyle="margin-left: 10px;"size="small"type="success"@click="submitUpload">上传到服务器</el-button><div slot="tip" class="el-upload__tip">支持上传 {{ strRebuild(fileType) }} 格式,且不超过 {{ fileSize }}M</div></el-upload></el-dialog>

点击按钮触发方法,open为true 上传弹窗出现:

handleUpload() {this.title = "XXXX";this.open = true;},

选择文件后,点击上传到服务器,触发以下方法:

 customUpload(file) {console.debug("进入上传方法");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);},

其中触发封装的请求方法:

export async function uploadFile(file) {try {console.log("上传资源参数:", file);// 尝试不同的路径格式const response = await request.post("/Resource/UploadFile", file);console.log("API响应:", 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){// 判断文件是否有内容if (file.Length == 0){Console.WriteLine("该文件无任何内容!!!");continue;}// 获取附件原名string fileName = file.FileName;// 如果是获取的含有路径的文件名,那么截取掉多余的,只剩下文件名和后缀名if (fileName.Contains("\\")){int index = fileName.LastIndexOf("\\");fileName = fileName.Substring(index + 1);}// 判断单个文件大于1Mlong fileSize = file.Length;if (fileSize > 1024 * 1024){Console.WriteLine($"文件大小为(单位字节):{fileSize}");Console.WriteLine("该文件大于1M");}// 构建完整保存路径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 接口类型对接前端的FormData类型。通过FileStream 类传输文件。

因为_webHostEnvironment.WebRootPath对应wwwroot,所以文件会保存在wwwroot目录下。

其实应该有对应的表格。上传的文件信息会保存在数据库里,这里图方便就没写。

下载:

下载的方法有很多种,这里展示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);});},

按钮调用:

<button @click="downloadFile('test.png')">下载文件2</button>

在方法里直接拼接了图片(其他文件类似)的url,会在浏览器中下载以下图片:

完整vue代码:

<template><div class="front-container"><div><h2>往昔峥嵘</h2><el-buttonsize="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-uploadref="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-buttonstyle="margin-left: 10px;"size="small"type="success"@click="submitUpload">上传到服务器</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"><BlogCardv-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: [],// 允许的文件类型,可依据实际需求增加格式fileType: ["xls","xlsx","pdf","doc","docx","txt","jpg","png","jpeg","zip",],//fileType: ["pdf", "doc", "zip"],// 运行上传文件大小,单位 MfileSize: 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("进入上传方法");const param = new FormData();param.append("files", file.file);// 模拟上传成功console.log("上传文件:", file);console.log("FormData:", param);uploadFile(param);// 模拟API调用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>

根据自己需要把其中报错,不相干的代码删减掉。

http://www.dtcms.com/a/511688.html

相关文章:

  • 建设门户网站预算做旅游网站多少钱
  • 【Rust创作】Rust 错误处理:从 panic 到优雅控制
  • 常见激活函数的Lipschitz连续证明
  • 专做皮具的网站网站建设公司排行榜
  • 第三次面试:C++实习开发
  • 公司网站内容更新该怎么做wordpress显示目录
  • 边界扫描测试原理 2 -- 边界扫描测试设备的构成
  • 如何入侵网站后台晴天影视
  • Linux top 命令使用说明
  • 研发图文档管理的革新:从无序到智能协同
  • springboot点餐系统的设计与实现(代码+数据库+LW)
  • ArcoDesignVue Select组件分离问题
  • Python开发:接口场景设计
  • 汽车网站flash模板定制高端网站建设
  • 【Ubuntu18.04 D435i RGB相机与IMU标定详细版(三)】
  • 单肩包自定义页面设计模板seo关键词优化软件app
  • 朊病毒检测市场:技术突破与公共卫生需求驱动下的全球增长
  • 思维清晰的基石:概念和命题解析
  • ubuntu中替换python版本
  • mybatis请求重试工具
  • 高速运放输入引脚并联电阻太小会怎样?
  • vue前端面试题——记录一次面试当中遇到的题(10)
  • 有没有做高仿手表的网站php网站地图
  • wordpress提交百度站长中建装饰集团有限公司官网
  • 牛客网 AI题​(一)机器学习 + 深度学习
  • 第一例:石头剪刀布的机器学习(xedu,示例15)
  • 【AI论文】D2E:基于桌面数据扩展视觉-动作预训练规模,以迁移至具身人工智能领域
  • 机器学习和深度学习模型训练流程
  • C++ STL——allocator
  • 开题报告--中美外贸企业电子商务模式的比较分析