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

【VUE案例练习】前端vue2+element-ui,后端nodo+express实现‘‘文件上传/删除‘‘功能

近期在做跟毕业设计相关的数据后台管理系统,其中的列表项展示有图片展示,添加/编辑功能有文件上传。

“文件上传/删除”也是我们平时开发会遇到的一个功能,这里分享个人的实现过程,与大家交流谈论~

一、准备工作

  • 本次案例使用的node版本是18.16.1
  • 前端vue2+element-ui
  • 后端使用node+express
  • 安装对应库:element-ui、axios、multer

注意:本篇重点介绍文件上传的相关功能,后端express的具体使用可以看我的express专栏~

express专栏

二、前端

文件上传组件,来自element-ui组件库

注意:自行安装组件库

Element - The world's most popular Vue UI framework

关于组件,有些展示和功能需要对应设置(比如文件上传的服务器地址,删除后端文件等等)才可以正常使用,所以我对代码进行了修改补充。

组件代码

<template><div><el-uploadref="upload"action="http://localhost:4000/api/upload"  //文件上传的接口list-type="picture-card":on-preview="handlePictureCardPreview":on-remove="handleRemove":file-list="fileList":on-change="handleFileChange":on-success="handleUploadSuccess":on-error="handleUploadError"name="file"><i class="el-icon-plus" /></el-upload><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="dialogImageUrl" alt=""></el-dialog></div>
</template>

 变量和相关函数

注意:需要安装axios(若安装则跳过)

npm install axios
<script>
import Axios from 'axios'
export default {data() {return {dialogImageUrl: '', //预览时展示的图片dialogVisible: false,fileList: [] // 用于存储文件列表}},methods: {// 生成文件预览 URLhandleFileChange(file, fileList) {file.url = URL.createObjectURL(file.raw)this.fileList = fileList},// 删除文件handleRemove(file, fileList) {this.fileList = fileList// 调用后端删除接口if (file.response && file.response.data) {this.deleteFile(file.response.data)} else {this.$message.warning('文件尚未上传成功,无法删除')}},// 预览图片handlePictureCardPreview(file) {this.dialogImageUrl = file.urlthis.dialogVisible = true},// 文件上传成功handleUploadSuccess(response, file) {console.log('文件上传成功', response)if (response.code === 0) {// 从后端响应中获取图片的 URLconst imageUrl = response.data// 更新 fileList 中的文件 URLconst index = this.fileList.findIndex(f => f.uid === file.uid)if (index !== -1) {this.fileList[index].url = imageUrlthis.fileList[index].response = response // 保存后端返回的响应}this.$message.success('文件上传成功')} else {this.$message.error('文件上传失败: ' + response.msg)}},// 文件上传失败handleUploadError(err, file) {console.error('文件上传失败', err)this.$message.error('文件上传失败')},deleteFile(filename) {// 去掉前缀 /public/static/upload/const pureFilename = filename.replace('/public/static/upload/', '')// 调用后端删除接口Axios.delete(`http://localhost:4000/api/upload/${pureFilename}`).then(response => {if (response.data.code === 0) {this.$message.success('文件删除成功')} else {this.$message.error('文件删除失败: ' + response.data.msg)}}).catch(err => {console.error('文件删除失败', err)this.$message.error('文件删除失败')})}}
}
</script>

完整代码

 注意看:''localhost:4000''相关字眼(关于后端接口的,下文会作介绍)

<template><div><el-uploadref="upload"action="http://localhost:4000/api/upload"list-type="picture-card":on-preview="handlePictureCardPreview":on-remove="handleRemove":file-list="fileList":on-change="handleFileChange":on-success="handleUploadSuccess":on-error="handleUploadError"name="file"><i class="el-icon-plus" /></el-upload><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="dialogImageUrl" alt=""></el-dialog></div>
</template><script>
import Axios from 'axios'
export default {data() {return {dialogImageUrl: '',dialogVisible: false,fileList: [] // 用于存储文件列表}},methods: {// 生成文件预览 URLhandleFileChange(file, fileList) {file.url = URL.createObjectURL(file.raw)this.fileList = fileList},// 删除文件handleRemove(file, fileList) {this.fileList = fileList// 调用后端删除接口if (file.response && file.response.data) {this.deleteFile(file.response.data)} else {this.$message.warning('文件尚未上传成功,无法删除')}},// 预览图片handlePictureCardPreview(file) {this.dialogImageUrl = file.urlthis.dialogVisible = true},// 文件上传成功handleUploadSuccess(response, file) {console.log('文件上传成功', response)if (response.code === 0) {// 从后端响应中获取图片的 URLconst imageUrl = response.data// 更新 fileList 中的文件 URLconst index = this.fileList.findIndex(f => f.uid === file.uid)if (index !== -1) {this.fileList[index].url = imageUrlthis.fileList[index].response = response // 保存后端返回的响应}this.$message.success('文件上传成功')} else {this.$message.error('文件上传失败: ' + response.msg)}},// 文件上传失败handleUploadError(err, file) {console.error('文件上传失败', err)this.$message.error('文件上传失败')},// 删除后端文件,参数传递的是文件名(经前端上传过后,返回给前端的文件名)deleteFile(filename) {// 去掉前缀 /public/static/upload/const pureFilename = filename.replace('/public/static/upload/', '')// 调用后端删除接口Axios.delete(`http://localhost:4000/api/upload/${pureFilename}`).then(response => {if (response.data.code === 0) {this.$message.success('文件删除成功')} else {this.$message.error('文件删除失败: ' + response.data.msg)}}).catch(err => {console.error('文件删除失败', err)this.$message.error('文件删除失败')})}}
}
</script><style>
.el-upload-list__item-thumbnail {width: 100%;height: 100%;object-fit: cover;
}
</style>

三、后端

1、搭建express应用

【express-generator】01-安装和基本使用

如果按照文章步骤(默认端口是3000,我这里设置成4000端口),则对应更换端口为4000,在创建的express项目的bin/www中进行修改。

2、新建文件夹以及文件

2.1、新建public/static/upload

这是存储上传文件的位置。

 2.2、新建routes/upload.js,用于撰写路由方法

安装multer,这是处理文件上传的相关库。

npm install multer

var express = require("express");
const multer = require("multer");
const { uploading } = require("../utils/tool");
const fs = require('fs');
const path = require('path');
var router = express.Router();// 文件上传接口
router.post("/", async function (req, res, next) {// single 方法里面书写上传控件的 name 值uploading.single("file")(req, res, function (err) {if (err instanceof multer.MulterError) {next("上传文件失败,请检查文件的大小,控制在 6MB 以内");} else {console.log("req.file>>>", req.file);const filePath = "/public/static/upload/" + req.file.filename;res.send({ code: 0, msg: "文件上传成功", data: filePath });}})
});// 文件删除接口
router.delete("/:filename", function (req, res, next) {const filename = req.params.filename;const filePath = path.join(__dirname, '../public/static/upload',filename);console.log("后端接收到的文件参数>>>",filename,"完整基本路径是>>>>",filePath);fs.unlink(filePath, (err) => {if (err) {console.error("删除文件失败", err);return res.status(500).send({ code: 1, msg: "删除文件失败" });}res.send({ code: 0, msg: "文件删除成功" });});
});module.exports = router;

2.3、新增utlis/tool.js,撰写工具类函数

const multer = require("multer");
const path = require("path");// 设置上传文件的引擎
const storage = multer.diskStorage({// 文件存储的位置destination: function (req, file, cb) {cb(null, __dirname + '/../public/static/upload');},// 上传到服务器的文件,文件名要做单独处理filename: function (req, file, cb) {// 获取文件名const basename = path.basename(file.originalname, path.extname(file.originalname));// 获取后缀名const extname = path.extname(file.originalname);// 构建新的名字const newName = basename + new Date().getTime() + Math.floor(Math.random() * 9000 + 1000) + extname;cb(null, newName);}
})module.exports.uploading = multer({storage: storage,limits: {fileSize: 6000000,files: 1}
})

 3、在app.js中引入和使用

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const cors = require('cors');
// 文件上传
const multer = require('multer');
const fs = require('fs');
// const path = require('path');var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var uploadRouter = require('./routes/upload');
var app = express();// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');// 允许所有来源访问
app.use(cors());// 文件上传
// const upload = multer({ dest: 'static/upload/' });
app.use(express.static(path.join(__dirname, 'public')));
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/api/upload/', uploadRouter);// error handler
app.use(function(err, req, res, next) {// set locals, only providing error in developmentres.locals.message = err.message;res.locals.error = req.app.get('env') === 'development' ? err : {};// render the error pageres.status(err.status || 500);res.render('error');
});module.exports = app;

四、测试

1、上传文件(图片)

 查看存储上传文件的位置

 2、删除文件(图片)

前端组件,鼠标进入到图片区域,点击删除按键

前端作出对应提示

最后前端的文件列表也为空,成功删除了文件。

后端查看文件夹,发现刚上传的文件由于前端的删除操作,也对应进行了删除。

 

 五、总结

一些注意点

express应用默认端口号是3000,而案例演示的是4000(因为一般情况,3000端口容易被其他代码程序给使用用,避免这种情况,可以使用一个新的端口号(或者把占用3000端口的程序都关闭))

关于文件上传的设置,涉及到的知识点比较多,比如fs.unlink,path相关的知识,需要大家自行进行补充了解,部分知识点可以参考下方这篇博客文章。

【NODE】01-fs和path常用知识点


如果有问题,请留言评论~

如果你喜欢这篇文章,留下你的点赞和收藏~ 

 

相关文章:

【VUE案例练习】前端vue2+element-ui,后端nodo+express实现‘‘文件上传/删除‘‘功能

近期在做跟毕业设计相关的数据后台管理系统&#xff0c;其中的列表项展示有图片展示&#xff0c;添加/编辑功能有文件上传。 “文件上传/删除”也是我们平时开发会遇到的一个功能&#xff0c;这里分享个人的实现过程&#xff0c;与大家交流谈论~ 一、准备工作 本次案例使用的…...

使用真实 Elasticsearch 进行高级集成测试

作者&#xff1a;来自 Elastic Piotr Przybyl 掌握高级 Elasticsearch 集成测试&#xff1a;更快、更智能、更优化。 在上一篇关于集成测试的文章中&#xff0c;我们介绍了如何通过改变数据初始化策略来缩短依赖于真实 Elasticsearch 的集成测试的执行时间。在本期中&#xff0…...

【R语言】函数

一、函数格式 如下所示&#xff1a; hello&#xff1a;函数名&#xff1b;function&#xff1a;定义的R对象是函数而不是其它变量&#xff1b;()&#xff1a;函数的输入参数&#xff0c;可以为空&#xff0c;也可以包含参数&#xff1b;{}&#xff1a;函数体&#xff0c;如果…...

Vue 3 30天精进之旅:Day 12 - 异步操作

在现代前端开发中&#xff0c;异步操作是一个非常常见的需求&#xff0c;例如从后端API获取数据、进行文件上传等任务。Vue 3 结合组合式API和Vuex可以方便地处理这些异步操作。今天我们将重点学习如何在Vue应用中进行异步操作&#xff0c;包括以下几个主题&#xff1a; 异步操…...

VSCode插件Live Server

简介&#xff1a;插件Live Server能够实现当我们在VSCode编辑器里修改 HTML、CSS 或者 JavaScript 文件时&#xff0c;它都能自动实时地刷新浏览器页面&#xff0c;让我们实时看到代码变化的效果。再也不用手动刷新浏览器了&#xff0c;节省了大量的开发过程耗时&#xff01; 1…...

50. 正点原子官方系统镜像烧写实验

一、Windows下使用OTG烧写系统 1、在Windos使用NXP提供的mfgtool来向开发烧写系统。需要用先将开发板的USB_OTG接口连接到电脑上。 Mfgtool工具是向板子先下载一个Linux系统&#xff0c;然后通过这个系统来完成烧写工作。 切记&#xff01;使用OTG烧写的时候要先把SD卡拔出来&…...

在C#中,什么是多态如何实现

在C#中,什么是多态?如何实现? C#中的多态性 多态性是面向对象编程的一个核心概念,他允许对象以多种形式表现.在C#中,多态主要通过虚方法,抽象方法和接口来实现. 多态性的存在使得同一个行为可以有多个不同的表达形式 即同一个接口可以使用不同的实例来执行不同的操作 虚方…...

搜索引擎友好:设计快速收录的网站架构

本文来自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/14.html 为了设计一个搜索引擎友好的网站架构&#xff0c;以实现快速收录&#xff0c;可以从以下几个方面入手&#xff1a; 一、清晰的目录结构与层级 合理划分内容&#xff1a;目录结构应…...

扩散模型(三)

相关阅读&#xff1a; 扩散模型&#xff08;一&#xff09; 扩散模型&#xff08;二&#xff09; Latent Variable Space 潜在扩散模型&#xff08;LDM&#xff1b;龙巴赫、布拉特曼等人&#xff0c;2022 年&#xff09;在潜在空间而非像素空间中运行扩散过程&#xff0c;这…...

it基础使用--5---git远程仓库

it基础使用–5—git远程仓库 1. 按顺序看 -git基础使用–1–版本控制的基本概念 -git基础使用–2–gti的基本概念 -git基础使用–3—安装和基本使用 -git基础使用–4—git分支和使用 2. 什么是远程仓库 在第一篇文章中&#xff0c;我们已经讲过了远程仓库&#xff0c;每个本…...

Baklib如何改变内容管理平台的未来推动创新与效率提升

内容概要 在信息爆炸的时代&#xff0c;内容管理平台成为了企业和个人不可或缺的工具。它通过高效组织、存储和发布内容&#xff0c;帮助用户有效地管理信息流。随着技术的发展&#xff0c;传统的内容管理平台逐渐暴露出灵活性不足、易用性差等局限性&#xff0c;这促使市场需…...

100.1 AI量化面试题:解释夏普比率(Sharpe Ratio)的计算方法及其在投资组合管理中的应用,并说明其局限性

目录 0. 承前1. 夏普比率的基本概念1.1 定义与计算方法1.2 实际计算示例 2. 在投资组合管理中的应用2.1 投资组合选择2.2 投资组合优化 3. 夏普比率的局限性3.1 统计假设的限制3.2 实践中的问题 4. 改进方案4.1 替代指标4.2 实践建议 5. 回答话术 0. 承前 如果想更加全面清晰地…...

Ubuntu 下 nginx-1.24.0 源码分析 ngx_debug_init();

目录 ngx_debug_init() 函数&#xff1a; NGX_LINUX 的定义&#xff1a; ngx_debug_init() 函数&#xff1a; ngx_debug_init() 函数定义在 src\os\unix 目录下的 ngx_linux_config.h 中 #define ngx_debug_init() 也就是说这个环境下的 main 函数中的 ngx_debug_init() 这…...

基于人脸识别的课堂考勤系统

该项目是一个基于人脸识别的课堂考勤系统&#xff0c;使用Python开发&#xff0c;结合了多种技术实现考勤功能。要开发类似的基于人脸识别的考勤系统&#xff0c;可参考以下步骤&#xff1a; 环境搭建&#xff1a;利用Anaconda创建虚拟环境&#xff0c;指定Python版本为3.8&am…...

开启 AI 学习之旅:从入门到精通

最近 AI 真的超火,不管是工作还是生活里,到处都能看到它的身影。好多小伙伴都跑来问我,到底该怎么学 AI 呢?今天我就把自己学习 AI 的经验和心得分享出来,希望能帮到想踏入 AI 领域的朋友们! 一、学习内容有哪些 (一)编程语言 Python 绝对是首选!它在 AI 领域的生态…...

13 尺寸结构模块(size.rs)

一、size.rs源码 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE…...

16.[前端开发]Day16-HTML+CSS阶段练习(网易云音乐五)

完整代码 网易云-main-left-rank&#xff08;排行榜&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&q…...

ARM嵌入式学习--第十天(UART)

--UART介绍 UART(Universal Asynchonous Receiver and Transmitter)通用异步接收器&#xff0c;是一种通用串行数据总线&#xff0c;用于异步通信。该总线双向通信&#xff0c;可以实现全双工传输和接收。在嵌入式设计中&#xff0c;UART用来与PC进行通信&#xff0c;包括与监控…...

MoonBit 编译器(留档学习)

MoonBit 编译器 MoonBit 是一个用户友好&#xff0c;构建快&#xff0c;产出质量高的编程语言。 MoonBit | Documentation | Tour | Core This is the source code repository for MoonBit, a programming language that is user-friendly, builds fast, and produces high q…...

【TypeScript】基础:数据类型

文章目录 TypeScript一、简介二、类型声明三、数据类型anyunknownnervervoidobjecttupleenumType一些特殊情况 TypeScript 是JavaScript的超集&#xff0c;代码量比JavaScript复杂、繁多&#xff1b;但是结构更清晰 一、简介 为什么需要TypeScript&#xff1f; JavaScript的…...

Unity游戏(Assault空对地打击)开发(3) 摄像机的控制

详细步骤 打开My Assets或者Package Manager。 选择Unity Registry。 搜索Cinemachine&#xff0c;找到 Cinemachine包&#xff0c;点击 Install按钮进行安装。 关闭窗口&#xff0c;新建一个FreeLook Camera&#xff0c;如下。 接着新建一个对象Pos&#xff0c;拖到Player下面…...

【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)

目录 1 -> 生命周期 1.1 -> 应用生命周期 1.2 -> 页面生命周期 2 -> 资源限定与访问 2.1 -> 资源限定词 2.2 -> 资源限定词的命名要求 2.3 -> 限定词与设备状态的匹配规则 2.4 -> 引用JS模块内resources资源 3 -> 多语言支持 3.1 -> 定…...

小程序-基础加强-自定义组件

前言 这次讲自定义组件 1. 准备今天要用到的项目 2. 初步创建并使用自定义组件 这样就成功在home中引入了test组件 在json中引用了这个组件才能用这个组件 现在我们来实现全局引用组件 在app.json这样使用就可以了 3. 自定义组件的样式 发现页面里面的文本和组件里面的文…...

尝试ai生成figma设计

当听到用ai 自动生成figma设计时&#xff0c;不免好奇这个是如何实现的。在查阅了不少资料后&#xff0c;有了一些想法。参考了&#xff1a;在figma上使用脚本自动生成色谱 这篇文章提供的主要思路是&#xff1a;可以通过脚本的方式构建figma设计。如果我们使用ai 生成figma脚本…...

【周易哲学】生辰八字入门讲解(八)

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解【周易哲学】生辰八字入门讲解&#xff0c;期待与你一同探索、学习、进步&#xff0c;一起卷起来叭&#xff01; 目录 一、六亲女命六亲星六亲宫位相互关系 男命六亲星…...

康德哲学与自组织思想的渊源:从《判断力批判》到系统论的桥梁

康德哲学与自组织思想的渊源&#xff1a;从《判断力批判》到系统论的桥梁 第一节&#xff1a;康德哲学中的自然目的论与自组织思想 核心内容&#xff1a; 康德哲学中的自然目的论和反思判断力概念&#xff0c;为现代系统论中的自组织思想提供了哲学基础&#xff0c;预见了复…...

解决whisper 本地运行时GPU 利用率不高的问题

我在windows 环境下本地运行whisper 模型&#xff0c;使用的是nivdia RTX4070 显卡&#xff0c;结果发现GPU 的利用率只有2% 。使用 import torch print(torch.cuda.is_available()) 返回TRUE。表示我的cuda 是可用的。 最后在github 的下列网页上找到了问题 极低的 GPU 利…...

【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具02

工具运行前的环境准备 1、登录用户管理员权限确认 工具使用的登录用户(-u后面的用户)&#xff0c;必须具有管理员的权限&#xff0c;因为需要读取系统表 例&#xff1a;Export.bat -s 10.48.111.12 -d db1 -u test -p test -schema dbo      2、Powershell的安全策略确认…...

java异常处理——try catch finally

单个异常处理 1.当try里的代码发生了catch里指定类型的异常之后&#xff0c;才会执行catch里的代码&#xff0c;程序正常执行到结尾 2.如果try里的代码发生了非catch指定类型的异常&#xff0c;则会强制停止程序&#xff0c;报错 3.finally修饰的代码一定会执行&#xff0c;除…...

【人工智能】使用Python和Hugging Face构建情感分析应用:从模型训练到Web部署

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 情感分析是自然语言处理(NLP)中的重要任务,它通过分析文本来判断情绪或观点的倾向性。近年来,预训练语言模型如BERT、GPT等在情感分析任…...