vue3头像上传组件

news/2024/11/29 9:01:54/

在这里插入图片描述

  • 用到了自定义组件v-model的双向绑定
  • 使用input的type=file这个原生html元素,通过监听change事件,获取到选择的文件(注意,选择完文件值后,要把这个隐藏的input的type=file元素的value置为空,否则,下次选择同样的图片,将不会触发change事件)
  • 使用axios + formData 上传文件
  • 后台做保存文件,以及静态资源目录映射即可

前端

AvatarUpload.vue

<template><div class="avatar-upload-wrapper"><!-- {{ modelValue }} --><div :class="['avatar-box',{'avatar-box-border':imgUrl?false:true}]" @click="clickAvatarBox" :style="{width: size + 'px',height: size + 'px'}"><!-- 隐藏的input的type=file --><input type="file" hidden ref="fileInputRef" accept="image/x-png,image/gif,image/jpeg,image/bmp" @change="changeFile"><img v-if="imgUrl" :src="imgUrl" alt=""><div v-else class="avatar-marker"><i class="iconfont icon-jiahao"></i></div></div></div></template><script setup>import Messager from '@/utils/messager'import axiosInstance from '@/utils/request'import { ref,reactive,watch } from 'vue'const emits = defineEmits(['update:modelValue'])const props = defineProps({size: {type: Number,default: 64},modelValue: {type: String,default: '' // 默认头像链接地址},maxSize: {type:Number,default: 5 // 默认最大不超过5M},serverUrl: {type:String,default: 'http://localhost:9091/static/img'} })const fileInputRef =ref(null)// const imgUrl = ref('http://localhost:9091/static/img/avatar/3026520210706112210298.png')const imgUrl = ref(props.modelValue)// console.log(imgUrl.value);// 监听头像url改变(打开弹框时, 传入的图片地址变化时, 同步修改imgUrl)watch(()=>props.modelValue,(newVal,oldVal)=>{imgUrl.value = newVal})function clickAvatarBox() {fileInputRef.value.click()}function changeFile() {console.log(123,fileInputRef.value.files[0].size);// 获取更改后的文件let file = fileInputRef.value.files[0]// 校验文件大小if(file.size / 1024 / 1024 > props.maxsize) {Messager.error('文件超过指定大小')} // 执行文件上传let formData = new FormData()formData.append("mfile", file)formData.append("type", "avatar")axiosInstance.post('/file/uploadFile',formData).then(res=>{console.log(res,'上传成功');imgUrl.value = props.serverUrl + reslet img = new Image()img.src = imgUrl.valueimg.onload = ()=>{emits('update:modelValue', imgUrl.value)}})}</script><style lang="scss" scoped>.avatar-box-border {border: 1px dashed #409eff !important;}.avatar-box {border-radius: 50%;margin-left: 20px;cursor: pointer;position: relative;border: 2px solid #eee;overflow: hidden;&:hover::before {content:'';display: block;position: absolute;width: 100%;height: 100%;background: rgba(0,0,0,.03);}img {width: 100%;height: 100%;object-fit: cover;}.avatar-marker {position: absolute;width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;color: #409eff;i.iconfont {font-size: 24px;}}}
</style>

使用AvatarUpload.vue

<el-dialog v-model="userDialogVisible" width="450"><el-form :model="userForm" :rules="userFormRules" label-width="80"><el-form-item label="昵称" prop="nickname"><el-input v-model="userForm.nickname" style="width: 300px;"></el-input></el-form-item><!-- 使用头像上传组件 --><el-form-item label="头像" prop="avatar"><avatar-upload v-model="userForm.avatar" /></el-form-item><el-form-item label="个性签名" prop="bio"><el-scrollbar><el-input type="textarea" :rows="3" v-model="userForm.bio" style="width: 300px;"></el-input></el-scrollbar></el-form-item><el-form-item label="网站链接" prop="website"><el-input v-model="userForm.website" style="width: 300px;"></el-input></el-form-item><el-form-item label="是否可用" prop="disabled"><el-switch v-model="userForm.disabled" :active-value="0" :inactive-value="1" active-color="#13ce66"inactive-color="#eaecf0"></el-switch></el-form-item><el-form-item><div style="margin-left: auto;"><el-button @click="userDialogVisible = false">取消</el-button><el-button type="primary" @click="handleSave">确定</el-button></div></el-form-item></el-form>
</el-dialog>

后端

上传接口

@PostMapping("uploadFile")
public Result<String> uploadFile(@RequestParam("mfile") MultipartFile mfile, String type) {return Result.ok(fileService.saveFile(mfile,type));
}@Override
public String saveFile(MultipartFile mfile, String type) {String filePath = FilePathEnum.type(type).getPathPrefix() + SnowflakeIdWorker.generateId().substring(0, 8) + mfile.getOriginalFilename();String targetFilePath = fileSavePath + filePath;try {mfile.transferTo(new File(targetFilePath));} catch (IOException e) {throw BizException.SAVE_FILE_ERR;}return filePath;
}

配置mvc

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("file:D:\\Projects\\boot-blog\\src\\main\\resources\\static\\");}
}

http://www.ppmy.cn/news/56194.html

相关文章

【Linux】基础IO——文件系统|软硬链接|动静态库

文章目录 一、磁盘1. 物理结构2. 存储结构3. 逻辑抽象结构 二、文件系统1. 文件系统的结构2. 查看文件3. 删除文件 三、软硬链接1. 软链接2. 硬链接3. ACM 时间 四、动静态库1. 动静态库的介绍2. 静态库的制作3. 动态库的制作4. 动态库的加载 一、磁盘 基于上篇博客所写到的文…

docker更改默认镜像和容器存储位置

Ubuntu版本&#xff1a;22.04 docker版本&#xff1a;23.0.5 无论是生成镜像还是加载镜像时&#xff0c;系统总提示var分区空间不足&#xff0c;无奈在网上寻找更改容器存储&#xff0c;不同的方法试了4、5种&#xff0c;总是出错&#xff0c;最后在一个老外的网站上发现新版本…

【C++初阶】类和对象(一)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C初阶】…

【SpringBoot系列】接收前端参数的几种方式

在Spring Boot中,有以下几种方式接收前端参数: RequestParam这是最基本的一种,通过请求参数名映射到方法的参数上,如: GetMapping("/test") public String test(RequestParam("name") String username) {// ... }然后请求URL为/test?namexxx。 Request…

淘系抓包流程(淘宝数据无法抓包解决方式)

淘系抓包流程 结合frida和adb工具以及mumu模拟器进行抓包。 具体的关系图: frida的安装 frida安装&#xff0c;直接安装官网的脚手架。frida官网使用python的pip安装&#xff0c;python > 3。 安装后使用查看版本命令来确认是否安装。 pip install frida-tools frida --ve…

双极性信号、正交信号和PAM信号通信系统matlab程序+仿真

资源地址&#xff1a; 双极性信号、正交信号和PAM信号通信系统MATLAB程序仿真资源-CSDN文库 部分程序及仿真图&#xff1a; clear all EbN00:10; %SNR的范围 for ii1:length(EbN0) SNREbN0(ii); %赋值给AWGN信道模块中的SNR sim(ex5); %运行仿…

javascript正则表达式大括号、中括号、小括号的作用以及应用场景

在JavaScript正则表达式中&#xff0c;大括号 {}、中括号 [] 和小括号 () 都有不同的作用和应用场景。 大括号 {} 在正则表达式中&#xff0c;大括号 {} 表示重复次数。以下是一些常见的应用场景&#xff1a; {n}&#xff1a;精确匹配出现的次数&#xff0c;例如 \d{3} 匹配…

关于电信设备进网许可制度若干改革举措的通告

Q&#xff1a;3月1日后&#xff0c;不再实行进网许可管理的11种电信设备是否还需要继续申请和使用标志&#xff1f; A&#xff1a;3月1日起&#xff0c;对不再实行进网许可管理的11种电信设备停止核发进网许可标志&#xff0c;已申请的标志可在证书有效期内继续使用。 Q&#…