【vue3】图片上传功能实现

news2025/2/27 8:30:00

本次功能使用的是vue3+elementplus+nodejs+multiparty实现的图片上传与使用。

属于自行摸索的部分,有很大改进地方。目前思路是图片和数据分别上传,在上传图片时返回图片地址,将地址保存到表单数据中,在获取图片时,通过地址读取图片。

问题点:图片添加后就直接会上传,导致重复。

一、前端部分

引入部分自行引入,地址:快速开始 | Element Plus (element-plus.org)

新建ceshi.vue

<el-form :model="form" label-width="auto" style="max-width: 800px">
<el-form-item label="上传封面">
			<el-upload drag class="avatar-uploader" method="post" action="/api/image" :show-file-list="false"
				:on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
				<img v-if="form.imgUrl" :src="`http://127.0.0.1:3000/getimg?url=${form.imgUrl}`" class="avatar" />
				<div v-else>
					<el-icon class="avatar-uploader-icon">
						<Plus />
					</el-icon>
					<div class="el-upload__text"> 上传文章封面图,可将图片拖到此处 或 <em>点击上传</em>
					</div>
				</div>
			</el-upload>
		</el-form-item>
</el-form>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'

import type { UploadProps } from 'element-plus'

// do not use same name with ref
	let form = ref({
		title: '',
		desc: '',
		html: '',
		categoryName: '',
		imgUrl: ''
	})
const imageUrl = ref('')
	//图片上传成功的钩子
	const handleAvatarSuccess : UploadProps['onSuccess'] = (
		response,
		uploadFile
	) => {
		imageUrl.value = URL.createObjectURL(uploadFile.raw!)
		form.value.imgUrl=response
	}
	//上传图片组件->上传图片之前触发的钩子函数
	const beforeAvatarUpload : UploadProps['beforeUpload'] = (rawFile) => {
		const allowedFormats = ['image/jpeg', 'image/png']; // 允许的文件格式
		 if (!allowedFormats.includes(rawFile.type)) {
		        this.$message.error('文件格式必须是 JPG 或 PNG!');
		        return false;
		    }
		 else if (rawFile.size / 1024 / 1024 > 2) {
			ElMessage.error('Avatar picture size can not exceed 2MB!')
			return false
		}
		return true
	}
</script>

二、后端部分

1.新建文件夹,在命令行输入express -e account(文件夹名称),即可创建项目。

在routers下index.js中----添加图片api


const multiparty = require('multiparty')

//添加图片
router.post('/image', function(req, res, next) {
	//添加图片的位置
	let form =new multiparty.Form({uploadDir:'./public/images'})
	form.parse(req, function(err, fields, files) {
		//返回图片的地址
		  res.json(files.file[0].path)
	});
});

获取图片的api

//获取图片
router.get('/getimg', (req, res, next) => {
	//获取图片地址
	let url=req.query.url
	//返回图片
	fs.readFile(`./${url}`,(err,data)=>{
		res.send(data)
	})
})

完整

var express = require('express');
var moment = require('moment');
var router = express.Router();
const fs=require('fs')
const multer = require('multer');
const multiparty=require('multiparty')
const accountModel = require('../models/accountModels.js');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

//获取全部文章信息账单
router.get('/getArticle', (req, res, next) => {
	 res.setHeader('Access-Control-Allow-Origin','*')
	accountModel.find().sort({createTime:-1}).then((data, err) => {
		if (err) {
			res.json({
				code: '1002',
				msg: '读取失败',
				data: null
			})
			return
		}
		res.json({
			code: '20000',
			msg: '找到了',
			data: data
		})


	});
})

//获取图片
router.get('/getimg', (req, res, next) => {
	//获取图片地址
	let url=req.query.url
	//返回图片
	fs.readFile(`./${url}`,(err,data)=>{
		res.send(data)
	})
})


//获取单个文章信息账单
router.get('/getArticle/:id', (req, res, next) => {
	let id = req.params.id
	
	accountModel.findById({
		_id: id
	}).then((data, err) => {
		
		if (err) {
			res.json({
				code: '1002',
				msg: '读取失败',
				data: null
			})
			return
		}
		res.json({
			code: '20000',
			msg: '找到了',
			data: data
		})


	});
})


//添加文章
router.post('/getArticle', function(req, res, next) {
	//插入数据库
	accountModel.create({...req.body,createTime:moment(req.body.createTime).toDate()}).then((data, err) => {
		if (err) {
			res.json({
				code: '1001',
				msg: '读取失败',
				data: null
			})
			return
		}
		res.json({
			code: '20000',
			msg: '读取成功',
			data: data
		})
	})

});

//添加图片
router.post('/image', function(req, res, next) {
	//添加图片的位置
	let form =new multiparty.Form({uploadDir:'./public/images'})
	form.parse(req, function(err, fields, files) {
		//返回图片的地址
		  res.json(files.file[0].path)
	});
});



//更新文章
router.patch('/getArticle/:id', function(req, res, next) {  
    // 获取id参数  
    const id = req.params.id;  
  
    // 假设你有一个 bodyParser 或类似的中间件来解析请求体  
    // 这里的 req.body 应该包含你想要更新的字段  
    const updateData = req.body; // 例如: { title: '新标题', content: '新内容' }  
  console.log(updateData);
    // 使用 updateOne 更新文档  
    accountModel.updateOne({  
        _id: id  
    }, {  
        $set: updateData // 使用 $set 操作符来更新字段  
    }).then(result => {  
        // result 包含 matchedCount 和 modifiedCount  
        if (result.modifiedCount === 0) {  
            // 如果没有文档被修改(可能是因为没有找到对应的 _id)  
            res.json({  
                code: '1002',  
                msg: '未找到或未更新任何文档',  
                data: null  
            });  
        } else {  
            // 如果想要返回更新后的文档,可以使用 findByIdAndUpdate 并设置 new: true  
            accountModel.findById(id, { new: true }).then(updatedDoc => {  
                res.json({  
                    code: '20000',  
                    msg: '更新成功',  
                    data: updatedDoc  
                });  
            }).catch(err => {  
                // 处理 findById 的错误  
                res.json({  
                    code: '1003',  
                    msg: '获取更新后的文档失败',  
                    data: null  
                });  
            });  
        }  
    }).catch(err => {  
        // 处理 updateOne 的错误  
        res.json({  
            code: '1001',  
            msg: '更新失败',  
            data: null  
        });  
    });  
});

//删除文章
router.delete('/getArticle/:id', function(req, res, next) {
	//获取id参数
	let id = req.params.id
	accountModel.deleteOne({
		_id: id
	}).then((data, err) => {
	
			if (err) {
				res.json({
					code: '1002',
					msg: '读取失败',
					data: null
				})
				return
			}
			res.json({
				code: '20000',
				msg: '读取成功',
				data: data
			})
		})
	
	});

module.exports = router;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能优化算法-蛇优化算法(SO)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 蛇优化算法 (Snake Optimization Algorithm, SO) 是一种基于群体智能的元启发式优化算法&#xff0c;它模拟了蛇的捕食行为、运动模式和社会互动&#xff0c;用于解决复杂的优化问题。 SO的工作机制主要包括&a…

跨平台设计利器:五款免费UI设计工具推荐

1、即时设计 即时设计是一款国产的在线UI设计工具&#xff0c;它以其强大的原型设计功能和丰富的交互效果而受到设计师的喜爱。即时设计支持300多种交互效果&#xff0c;可以帮助设计师快速构建高保真原型。它还提供了设计交付功能&#xff0c;允许设计师直接在平台上创建用户…

版权科普:版权保护的常见误区,你中招了吗?

在当今信息爆炸的时代&#xff0c;版权保护成为了一个备受关注的话题。然而&#xff0c;对于版权保护&#xff0c;很多人存在着一些误解和误区。 首先&#xff0c;让我们来明确一下什么是版权保护。 版权保护指的是对文学、艺术和科学领域内具有独创性并能以某种有式复制的智力…

Linux系统使用NFS挂载共享目录

一、目的 服务器A 共享目录 /data 服务器B 挂载服务器A的目录 /data 服务器C 挂载服务器A的目录 /data … 上面的/data 只是举例&#xff0c;也可以是自定义的路径 二、常见的使用场景 ①、应用多实例多机器部署的情况下&#xff0c;有一些下载或者上传的模板文件&#xff…

taozige/Java语言的Netty框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统源码

云快充协议云快充1.5协议云快充1.6云快充协议开源代码云快充底层协议云快充桩直连桩直连协议充电桩协议云快充源码 介绍 云快充协议云快充1.5协议云快充1.6云快充协议开源代码云快充底层协议云快充桩直连桩直连协议充电桩协议云快充源码 软件架构 1、提供云快充底层桩直连协…

提升职场办公效率的电脑桌面悬浮窗便签有什么?

电脑桌面悬浮窗便签软件能够帮助我们更好地管理日常任务、记录灵感瞬间&#xff0c;提升职场办公效率&#xff0c;并且保持工作区的整洁。这类软件通常具备以下特点&#xff1a;简易实用、快速记录、功能齐全、以及跨平台同步功能等等。今天为大家推荐一款简单好用的电脑桌面悬…

高可用之限流-06-slide window 滑动窗口 sentinel 源码

限流系列 开源组件 rate-limit: 限流 高可用之限流-01-入门介绍 高可用之限流-02-如何设计限流框架 高可用之限流-03-Semaphore 信号量做限流 高可用之限流-04-fixed window 固定窗口 高可用之限流-05-slide window 滑动窗口 高可用之限流-06-slide window 滑动窗口 sen…

二维码:理解二维码 / 生成二维码 / 小程序支持哪种类型的二维码 / 小程序识别GS1码

一、理解二维码 1.1、概念 二维码&#xff08;2-dimensional bar code&#xff09;&#xff0c;又称二维条码&#xff0c;最早发源于日本&#xff0c;它是用某种特定的几何图形按一定规律在平面&#xff08;二维方向上&#xff09;分布的黑白相间的图形记录数据符号信息的&am…

10月15日 -- 11月15日 ,参与《人工智能导论》学习打卡赢B站大会员

一、活动参与地址 点击链接进行活动报名>>>https://momodel.cn/classroom/course/detail?id6173911eab37f12b14daf4a8&activeKeyinfo&srcbef3adb478 二、活动详情 进入链接点击报名&#xff0c;仅需每天参与吴超老师的《人工智能导论》打卡活动&#xff0…

day11-SpringMVC

一、SpringMVC 1.SpringMVC流程分析 2.各种注解 3.接收请求参数 3.1 简单类型 3.2 对象类型 3.3 数组类型 3.4 集合类型 3.5 日期类型 3.6 json参数类型 3.7 路径参数 二、统一异常处理 三、Restful

一个月学会Java 第16天 注解和异常处理

Day16 注解和异常处理 为什么一定要标注是元注解呢&#xff0c;这个原因其实非常的简单&#xff0c;因为注解现在还不能写&#xff0c;想要使用注解达到SpringMVC和SpringBoot的等级需要使用反射&#xff0c;但是反射我们现在还不会&#xff0c;所以就先讲讲最基本的元注解。 第…

MOS管的电路应用

MOS管的电路应用 MOS管的选型参考 1、MOS管类型 一般选择增强型NMOS管&#xff0c;同等工艺条件下&#xff0c;导通电阻Ron更小&#xff0c;发热更低&#xff0c;允许通过的电流更大&#xff0c;型号也更多。 2、Vgs电压 需要考虑开启电压&#xff0c;驱动电压&#xff0c;极…

每日一刷——10.14——括号匹配(手写栈来实现)

栈与队列题目 第一题 题目 问题描述】设计一个算法判别一个算术表达式的圆括号是否正确配对 【输入形式】一个以为结尾的算术表达式 【输出形式】若配对&#xff0c;则输出圆括号的对数&#xff1b;否则输出no 【样例输入】 (ab)/(cd) 【样例输出】 2 【样例说明】共有两对括…

带隙基准Bandgap电路学习(三)

一、导入器件到版图中 从原理图中导入器件&#xff1a; Connectivity——>Generate——>All From Source I/O Pins暂不添加&#xff0c;后面自己画 PR&#xff08;Primary Region&#xff09;Boundary: 通常是用来定义芯片设计中某些关键区域的轮廓&#xff0c;比…

揭秘数字时代的安全守护者:深入探索RSA加密算法的奥秘

目录 引言 一、什么是RSA&#xff1f; 二、RSA 的基本原理 三、RSA 加密的基本步骤 1、加密过程 2、解密过程 四、RSA例子 五、RSA 的特点 六、RSA 的安全性 七、RSA 的实际应用 总结 引言 在当今的信息化社会&#xff0c;数据的安全性和隐私保护已…

外包干了两年,女朋友跟别人跑了

在这个瞬息万变的IT行业&#xff0c;不进则退的道理&#xff0c;我算是深刻体会到了。作为一名本科生&#xff0c;21年通过校招&#xff0c;我幸运地踏入了广州某知名软件公司的大门&#xff0c;成为了一名功能测试工程师。那时的我&#xff0c;满怀激情与梦想&#xff0c;以为…

Neuromnia是一家创新的AI平台用Llama为自闭症护理领域带来全新解决方案

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Linux——Harbor(容器镜像 管理项目)

镜像拉取存在一定的问题&#xff0c;出现原因在于&#xff1a; 使用官方公共仓库中的镜像。 拉取的镜像&#xff0c;主要保存在一下仓库中&#xff1a; docker.io //Docker hub 最大的官方维护的公共镜像仓库&#xff0c;一般都会提供所有项目的最新版镜像&#xff0c;镜像…

SIGformer: Sign-aware Graph Transformer for Recommendation

SIGformer: Sign-aware Graph Transformer for Recommendation&#xff08;Sigir24&#xff09; 摘要 在推荐系统中&#xff0c;大多数基于图的方法只关注用户的正面反馈&#xff0c;而忽略了有价值的负面反馈。将正反馈和负反馈结合起来形成一个带符号的图&#xff0c;可以更…

【AI论文精读5】知识图谱与LLM结合的路线图-P2

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI大项目】【AI应用】 P1 4 知识图谱增强的LLMs 大语言模型&#xff08;LLMs&#xff09;在许多自然语言处理任务中取得了令人期待的结果。然而&#xff0c;LLMs因缺乏实用知识和在推理过程中容易产生事实性错误而受到…