- 用到了
自定义组件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\\");}
}