5.7 KiB
5.7 KiB
头像上传功能实现说明
完成时间
2026-01-27
功能概述
将Profile页面的头像上传功能从Base64编码改为调用后端文件上传接口,获取云存储URL。
实现细节
1. API接口配置
在 lottery-app/src/api/index.js 中已添加文件上传接口:
// 上传文件
uploadFile(file) {
const formData = new FormData()
formData.append('file', file)
return api.post('/file/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
接口地址: POST /api/file/upload
请求格式: multipart/form-data
响应格式:
{
"code": 0,
"data": {
"fileName": "a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpg",
"fileUrl": "https://yicaishuzhi-1326058838.cos.ap-beijing.myqcloud.com/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpg",
"originalFilename": "avatar.jpg"
},
"message": "ok"
}
2. 数据状态管理
在 lottery-app/src/views/Profile.vue 的 data 中添加了上传状态标志:
data() {
return {
// ... 其他属性
uploadingAvatar: false, // 新增:头像上传状态
// ...
}
}
3. 头像上传方法实现
修改了 handleAvatarChange 方法:
主要改动:
- 从读取文件为Base64改为调用
lotteryApi.uploadFile(file)接口 - 添加上传状态管理 (
uploadingAvatar) - 从响应中获取
fileUrl并设置到editForm.userAvatar - 添加完整的错误处理和用户提示
- 清空文件输入框,允许重新选择同一文件
代码实现:
async handleAvatarChange(event) {
const file = event.target.files[0]
if (!file) return
// 验证文件类型
if (!file.type.startsWith('image/')) {
this.$toast.error('请选择图片文件')
return
}
// 验证文件大小(限制2MB)
if (file.size > 2 * 1024 * 1024) {
this.$toast.error('图片大小不能超过2MB')
return
}
this.uploadingAvatar = true
try {
// 显示上传提示
this.$toast.info('正在上传头像...')
// 调用上传接口
const response = await lotteryApi.uploadFile(file)
if (response.code === 0 && response.data && response.data.fileUrl) {
// 上传成功,设置头像URL
this.editForm.userAvatar = response.data.fileUrl
this.$toast.success('头像上传成功!')
} else {
this.$toast.error(response.message || '头像上传失败')
}
} catch (error) {
console.error('头像上传失败:', error)
this.$toast.error('头像上传失败,请稍后重试')
} finally {
this.uploadingAvatar = false
// 清空文件输入框,允许重新选择同一文件
event.target.value = ''
}
}
4. UI交互优化
4.1 头像预览区域
添加了上传中的遮罩层和加载动画:
<div class="avatar-preview" :class="{ 'uploading': uploadingAvatar }">
<img v-if="editForm.userAvatar" :src="editForm.userAvatar" alt="头像" />
<div v-else class="avatar-placeholder">{{ editForm.userName ? editForm.userName.charAt(0) : 'U' }}</div>
<div v-if="uploadingAvatar" class="upload-overlay">
<div class="upload-spinner"></div>
</div>
</div>
4.2 上传按钮
添加了禁用状态和文字变化:
<button class="upload-btn" @click="triggerFileUpload" :disabled="uploadingAvatar">
<svg viewBox="0 0 24 24" class="camera-icon">
<!-- SVG路径 -->
</svg>
{{ uploadingAvatar ? '上传中...' : '更换头像' }}
</button>
4.3 CSS样式
添加了以下样式:
/* 禁用状态 */
.upload-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
background: #f5f5f5;
border-color: #e0e6ed;
color: #999;
}
/* 上传遮罩层 */
.upload-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
/* 加载动画 */
.upload-spinner {
width: 24px;
height: 24px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
功能特性
✅ 已实现
-
文件验证
- 验证文件类型(仅允许图片)
- 验证文件大小(限制2MB)
-
上传流程
- 调用后端上传接口
- 获取云存储URL
- 更新头像预览
-
用户反馈
- 上传中提示
- 上传成功提示
- 上传失败提示
- 按钮禁用状态
- 加载动画
-
错误处理
- 网络错误处理
- 接口错误处理
- 文件验证错误处理
-
用户体验
- 上传中显示遮罩和加载动画
- 按钮文字动态变化
- 清空文件输入框,允许重新选择
测试建议
1. 功能测试
- 选择图片文件,验证上传成功
- 选择非图片文件,验证错误提示
- 选择超过2MB的图片,验证错误提示
- 上传过程中验证按钮禁用
- 上传成功后验证头像更新
- 保存用户信息后验证头像持久化
2. UI测试
- 验证上传中的遮罩层显示
- 验证加载动画正常运行
- 验证按钮文字变化
- 验证按钮禁用样式
3. 错误场景测试
- 网络断开时上传
- 后端接口返回错误
- 上传超时处理
相关文件
lottery-app/src/views/Profile.vue- 主要实现文件lottery-app/src/api/index.js- API接口定义
开发服务器
当前运行在: http://localhost:5174/
注意事项
- 确保后端
/api/file/upload接口正常运行 - 确保云存储服务配置正确
- 上传的图片URL需要支持跨域访问
- 建议在生产环境中添加图片压缩功能