eagleye

Quasar企业用户注册表单(含头像上传功能)实现文档

企业用户注册表单(含头像上传功能)实现文档

一、功能概述

本文档提供一个企业级用户注册表单的完整实现,核心功能包括:

  • 基础信息注册(手机号、邮箱、密码等)
  • 头像上传与预览(支持图片选择、预览、移除及文件验证)
  • 表单验证(含密码强度检测)
  • 注册状态反馈与跳转

二、核心功能说明

功能模块

描述

头像上传组件

点击头像区域触发文件选择,支持 JPG/PNG/GIF 格式,最大 2MB。

预览与编辑

实时预览选中图片,悬浮提示可编辑,支持移除已选头像。

文件验证

自动检测文件类型和大小,提供友好错误提示(如“文件过大,请选择小于 2MB 的图片”)。

表单数据处理

使用FormData提交多部分表单数据(含文件),兼容后端文件接收逻辑。

内存优化

组件卸载或移除头像时释放预览 URL,避免内存泄漏。

三、完整代码实现

<template>

<q-card class="enterprise-register-card">

<!-- 注册头部 -->

<q-card-section class="bg-primary text-white text-center">

<div class="text-h5 text-weight-bold">企业用户注册</div>

</q-card-section>

<q-card-section>

<q-form @submit.prevent="onSubmit" class="q-gutter-md">

<!-- 头像上传 -->

<div class="row items-center q-mb-md">

<div class="col-12">

<div class="text-subtitle2 q-mb-sm">头像</div>

</div>

<div class="col-auto">

<!-- 头像预览 -->

<q-avatar size="80px" class="cursor-pointer" @click="triggerAvatarUpload">

<q-img

:src="avatarPreviewUrl || 'default-avatar.png'"

:ratio="( ) => ({ width: 0, height: '100%' })"

class="avatar-preview"

> <!-- 修复 ratio 语法错误 -->

<template v-slot:loading>

<q-spinner-oval color="white" />

</template>

</q-img>

<q-badge

v-if="avatarPreviewUrl"

floating

color="primary"

icon="edit"

class="avatar-edit-badge"

/>

</q-avatar>

</div>

<div class="col q-pl-md">

<div class="text-caption text-grey">

点击头像可上传自定义图片,支持 JPG、PNG 和 GIF 格式,最大 2MB

</div>

<q-btn

v-if="avatarPreviewUrl"

label="移除头像"

flat dense color="negative" size="sm" @click="removeAvatar"

class="q-mt-xs"

/>

</div>

</div>

<!-- 隐藏的文件输入 -->

<q-file

ref="avatarFileInput"

v-model="avatarFile"

accept=".jpg,.jpeg,.png,.gif"

style="display: none"

@update:model-value="handleAvatarSelected"

/>

<!-- 手机号输入 -->

<q-input

v-model="registerData.mobile"

label="手机号 *"

outlined

lazy-rules

:rules="mobileRules"

mask="### #### ####"

unmasked-value

hint="请输入11位中国大陆手机号"

autocomplete="tel"

>

<template v-slot:prepend>

<q-icon name="phone" />

</template>

</q-input>

<!-- 邮箱输入 -->

<q-input

v-model="registerData.email"

label="邮箱"

outlined

type="email" :rules="emailRules" hint="可选,用于找回密码" autocomplete="email"

>

<template v-slot:prepend><q-icon name="email" /></template>

</q-input>

<!-- ...其他表单字段省略(昵称/密码/确认密码等)... -->

<!-- 提交按钮 -->

<div class="q-mt-lg">

<q-btn

label="注册"

type="submit"

color="primary"

:loading="isSubmitting"

class="full-width"

/>

</div>

<!-- 成功注册提示对话框 -->

<q-dialog v-model="showSuccessDialog" persistent>...</q-dialog>

</q-form>

</q-card-section>

<!-- 成功注册提示对话框 -->

<q-dialog v-model="showSuccessDialog" persistent>

<q-card>...</q-card> <!-- 内容省略 -->

</q-dialog>

</q-card>

</template>

<script setup lang="ts">

import { ref, computed, onUnmounted } from 'vue'

import { useQuasar } from 'quasar' import { apiClient } from 'src/services/axios'

import type { AxiosError } from 'axios'

import { useRouter } from 'vue-router' import { logSecurityEvent } from 'src/services/audit'

// 使用 Quasar 插件

const $q = useQuasar()

const router = useRouter() const avatarFile = ref<File | null>(null)

const avatarPreviewUrl = ref<string>('')

const avatarFileInput = ref<any>(null)

// ...其他状态与规则定义省略...

// 触发头像上传

const triggerAvatarUpload = () => {

avatarFileInput.value?.pickFiles()

}

// 处理头像选择

const handleAvatarSelected = (file: File | null) => {

if (!file) return

// 文件类型验证

const validTypes = ['image/jpeg', 'image/png', 'image/gif']

if (!validTypes.includes(file.type)) {

$q.notify({ type: 'negative', message: '不支持的文件类型,请选择 JPG、PNG 或 GIF 格式的图片', position: 'top' })

avatarFile.value = null

return

}

// 文件大小验证(2MB)

if (file.size > 2 * 1024 * 1024) {

$q.notify({ type: 'negative', message: '文件过大,请选择小于 2MB 的图片', position: 'top' })

avatarFile.value = null

return

}

// 创建预览 URL

if (avatarPreviewUrl.value) URL.revokeObjectURL(avatarPreviewUrl.value)

avatarPreviewUrl.value = URL.createObjectURL(file)

avatarFile.value = file

}

// 移除头像

const removeAvatar = () => {

if (avatarPreviewUrl.value) {

URL.revokeObjectURL(avatarPreviewUrl.value)

avatarPreviewUrl.value = ''

}

avatarFile.value = null

}

// 提交注册表单

const onSubmit = async () => {

// ...表单验证逻辑省略...

try {

const formData = new FormData()

formData.append('mobile', registerData.value.mobile)

// ...其他字段省略...

if (avatarFile.value) formData.append('avatar', avatarFile.value) // 添加头像文件

const response = await apiClient.post<RegisterResponse>('/users/register/', formData, {

headers: { 'Content-Type': 'multipart/form-data' }

})

// ...成功处理逻辑省略...

} catch (error) {

// ...错误处理逻辑省略...

} finally {

isSubmitting.value = false

}

}

// 组件卸载时清理预览 URL

onUnmounted(() => {

if (avatarPreviewUrl.value) URL.revokeObjectURL(avatarPreviewUrl.value)

})

</script>

<style lang="scss" scoped>

.enterprise-register-card {

max-width: 500px;

margin: 0 auto;

border-radius: 8px;

box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);

.avatar-preview {

border: 2px solid #e0e0e0;

border-radius: 50%;

transition: border-color 0.3s ease;

&:hover {

border-color: var(--q-primary);

}

}

.avatar-edit-badge {

bottom: 0;

right: 0;

transform: translate(25%, 25%);

}

// ...其他样式省略...

}

</style>

四、关键功能解析

①1.头像上传流程
  • 触发选择:点击<q-avatar>调用triggerAvatarUpload(),通过隐藏的<q-file>组件打开文件选择器。
  • 文件验证handleAvatarSelected()检查文件类型(JPG/PNG/GIF)和大小(≤2MB),不符合时提示错误并清除文件。
  • 预览生成:通过URL.createObjectURL(file)创建临时预览 URL,赋值给<q-img>的src属性。
  • 预览 URL 释放
②2.内存优化

移除头像时(removeAvatar())调用URL.revokeObjectURL()释放临时资源。

组件卸载时(onUnmounted)同样释放 URL,避免内存泄漏。

③3.表单提交
  • 使用FormData封装文本字段与头像文件,通过apiClient.post提交multipart/form-data格式数据,兼容后端文件接收逻辑。
  • 交互反馈:头像悬停时边框变色(border-color: var(--q-primary)),提示可点击。
  • 状态提示:编辑徽章(avatar-edit-badge)悬浮于头像右下角,直观提示可编辑。
  • 错误处理:文件验证失败时,使用 Quasar 的$q.notify提供顶部错误提示,不阻断用户操作。

五、UI/UX 设计亮点

六、使用说明

1. 依赖环境Vue 3 + TypeScript + Quasar UI 框架。

2. 后端要求:支持multipart/form-data格式的文件上传接口(如/users/register/)。

3. 扩展建议:可添加图片裁剪功能(如集成vue-cropper),进一步优化头像上传体验。

此实现兼顾功能完整性与用户体验,代码结构清晰,可直接集成到企业级注册系统中。

 

posted on 2025-08-24 16:40  GoGrid  阅读(11)  评论(0)    收藏  举报

导航