eagleye

注册页面组件(带自动跳转功能)存档文档

注册页面组件(带自动跳转功能)存档文档

一、组件概述

组件名称RegisterPage.vue

功能定位:企业级用户注册表单,支持手机号/邮箱双因子注册、密码强度检测、GDPR合规同意及注册成功后自动跳转登录功能,基于Vue 3 + TypeScript + Quasar框架实现。

核心价值

  • 表单安全优化:完整的autocomplete属性配置,符合W3C标准
  • 智能跳转机制:注册成功后自动导向登录页面,提升用户体验
  • 密码安全策略:实时强度检测(弱/中/强/非常强)及多维度规则校验
  • 企业级合规:内置GDPR数据保护条例同意机制
  • 响应式设计:适配移动端/桌面端的表单布局
  • autocomplete属性优化

二、核心功能模块

1. 智能表单控制

手机号:autocomplete="tel"(优化移动端数字键盘唤起)

邮箱:autocomplete="email"(自动填充邮箱客户端数据)

昵称:autocomplete="nickname"(支持浏览器个人信息管理)

密码字段:autocomplete="new-password"(防止密码管理器错误填充)

  • 注册成功自动跳转

基于Vue Router的命名路由跳转({ name: 'Login' })

成功对话框确认后触发redirectToLogin方法

o 跳转前自动重置表单数据,确保下次注册环境干净

2. 密码安全体系

  • 强度实时检测

const passwordStrength = computed(() => {

let strength = 0

// 长度得分(最高40分)

if (password.length >= 12) strength += 30

if (password.length >= 16) strength += 10

// 字符种类得分(最高60分)

if (/[a-z]/.test(password)) strength += 10

if (/[A-Z]/.test(password)) strength += 10

if (/[0-9]/.test(password)) strength += 10

if (/[^A-Za-z0-9]/.test(password)) strength += 20

// 防常用密码加分(10分)

if (!commonPasswords.some(p => password.toLowerCase().includes(p))) strength += 10

return Math.min(strength, 100)

})

  • 多维度验证规则

const passwordRules = [

(val) => !!val || '密码不能为空',

(val) => val.length >= 12 || '密码长度至少为12位',

(val) => /[a-z]/.test(val) || '必须包含小写字母',

(val) => /[A-Z]/.test(val) || '必须包含大写字母',

(val) => /[0-9]/.test(val) || '必须包含数字',

(val) => /[^A-Za-z0-9]/.test(val) || '必须包含特殊字符',

]

3. 企业级用户体验优化

  • 表单交互反馈

手机号掩码:mask="### #### ####"(格式化显示)

密码可见性切换:双图标切换(visibility/visibility_off)

实时错误提示:字段级验证反馈(如"两次输入的密码不一致")

  • 合规性控制

o GDPR强制同意:未勾选时阻止表单提交

数据脱敏处理:注册成功后仅显示用户ID(隐藏敏感信息)

操作审计准备:预留用户ID记录字段(registeredUserId)

三、完整代码实现

<template>

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

<q-card-section>

<div class="text-h5 text-center q-mb-md">企业用户注册</div>

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

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

<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>

<!-- 昵称输入 -->

<q-input

v-model="registerData.nickname"

label="昵称"

outlined

:rules="nicknameRules"

hint="将用于系统显示您的名称"

autocomplete="nickname"

>

<template v-slot:prepend>

<q-icon name="person" />

</template>

</q-input>

<!-- 密码输入 -->

<q-input

v-model="registerData.password"

label="密码 *"

outlined

:type="isPwdVisible ? 'text' : 'password'"

:rules="passwordRules"

hint="至少12位,包含大小写字母、数字和特殊字符"

autocomplete="new-password"

>

<template v-slot:prepend>

<q-icon name="lock" />

</template>

<template v-slot:append>

<q-icon

:name="isPwdVisible ? 'visibility_off' : 'visibility'"

class="cursor-pointer"

@click="isPwdVisible = !isPwdVisible"

/>

</template>

</q-input>

<!-- 密码强度指示器 -->

<div class="row items-center">

<q-linear-progress

:value="passwordStrength / 100"

:color="passwordStrengthColor"

class="col"

/>

<div class="q-ml-sm text-caption">

{{ passwordStrengthLabel }}

</div>

</div>

<!-- 确认密码 -->

<q-input

v-model="registerData.passwordConfirm"

label="确认密码 *"

outlined

:type="isConfirmPwdVisible ? 'text' : 'password'"

:rules="confirmPasswordRules"

autocomplete="new-password"

>

<template v-slot:prepend>

<q-icon name="lock" />

</template>

<template v-slot:append>

<q-icon

:name="isConfirmPwdVisible ? 'visibility_off' : 'visibility'"

class="cursor-pointer"

@click="isConfirmPwdVisible = !isConfirmPwdVisible"

/>

</template>

</q-input>

<!-- GDPR 同意 -->

<q-checkbox

v-model="gdprConsent"

label="我同意遵守 GDPR 数据保护条例"

:rules="[(val: boolean) => val || '必须同意GDPR条例才能注册']"

/>

<!-- 提交按钮 -->

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

<q-btn

label="注册"

type="submit"

color="primary"

:loading="isSubmitting"

class="full-width"

/>

</div>

</q-form>

</q-card-section>

<!-- 成功注册提示 -->

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

<q-card>

<q-card-section class="row items-center">

<q-avatar icon="check_circle" color="positive" text-color="white" />

<span class="q-ml-sm">用户注册成功!</span>

</q-card-section>

<q-card-section>

<p>

您的用户ID: <strong>{{ registeredUserId }}</strong>

</p>

<p>请妥善保管您的账号信息</p>

</q-card-section>

<q-card-actions align="right">

<q-btn

flat

label="确定"

color="primary"

v-close-popup

@click="redirectToLogin"

/>

</q-card-actions>

</q-card>

</q-dialog>

</q-card>

</template>

<script setup lang="ts">

import { ref, computed } from 'vue'

import { useQuasar } from 'quasar'

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

import type { AxiosError } from 'axios'

import { useRouter } from 'vue-router'

// 使用 Quasar 插件

const $q = useQuasar()

const router = useRouter()

// 注册表单数据类型

interface RegisterFormData {

mobile: string

email: string

nickname: string

password: string

passwordConfirm: string

}

// 注册响应类型

interface RegisterResponse {

status: string

message: string

user_id: string

}

// 表单数据

const registerData = ref<RegisterFormData>({

mobile: '',

email: '',

nickname: '',

password: '',

passwordConfirm: '',

})

// 状态控制

const isSubmitting = ref(false)

const isPwdVisible = ref(false)

const isConfirmPwdVisible = ref(false)

const gdprConsent = ref(false)

const showSuccessDialog = ref(false)

const registeredUserId = ref('')

// 验证规则 - 手机号

const mobileRules = [

(val: string) => !!val || '手机号不能为空',

(val: string) => /^1[3-9]\d{9}$/.test(val) || '请输入有效的手机号',

]

// 验证规则 - 邮箱

const emailRules = [

(val: string) => !val || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val) || '请输入有效的邮箱地址',

]

// 验证规则 - 昵称

const nicknameRules = [(val: string) => !val || val.length <= 20 || '昵称不能超过20个字符']

// 验证规则 - 密码

const passwordRules = [

(val: string) => !!val || '密码不能为空',

(val: string) => val.length >= 12 || '密码长度至少为12位',

(val: string) => /[a-z]/.test(val) || '必须包含小写字母',

(val: string) => /[A-Z]/.test(val) || '必须包含大写字母',

(val: string) => /[0-9]/.test(val) || '必须包含数字',

(val: string) => /[^A-Za-z0-9]/.test(val) || '必须包含特殊字符',

]

// 验证规则 - 确认密码

const confirmPasswordRules = [

(val: string) => !!val || '请确认密码',

(val: string) => val === registerData.value.password || '两次输入的密码不一致',

]

// 密码强度计算

const passwordStrength = computed(() => {

const password = registerData.value.password

if (!password) return 0

let strength = 0

// 长度得分

if (password.length >= 12) strength += 30

if (password.length >= 16) strength += 10

// 字符种类得分

if (/[a-z]/.test(password)) strength += 10

if (/[A-Z]/.test(password)) strength += 10

if (/[0-9]/.test(password)) strength += 10

if (/[^A-Za-z0-9]/.test(password)) strength += 20

// 避免常用密码

const commonPasswords = ['password', '123456', 'qwerty', 'admin']

if (!commonPasswords.some((p) => password.toLowerCase().includes(p))) {

strength += 10

}

return Math.min(strength, 100)

})

// 密码强度标签

const passwordStrengthLabel = computed(() => {

const strength = passwordStrength.value

if (strength < 40) return '弱'

if (strength < 70) return '中'

if (strength < 90) return '强'

return '非常强'

})

// 密码强度颜色

const passwordStrengthColor = computed(() => {

const strength = passwordStrength.value

if (strength < 40) return 'negative'

if (strength < 70) return 'warning'

return 'positive'

})

// 跳转到登录页面

const redirectToLogin = () => {

// 使用命名路由跳转到登录页面

router.push({ name: 'Login' })

}

// 提交注册表单

const onSubmit = async () => {

if (!gdprConsent.value) {

$q.notify({

type: 'warning',

message: '请同意GDPR数据保护条例',

})

return

}

isSubmitting.value = true

try {

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

mobile: registerData.value.mobile,

email: registerData.value.email,

nickname: registerData.value.nickname,

password: registerData.value.password,

password_confirm: registerData.value.passwordConfirm,

})

if (response.data.status === 'success') {

registeredUserId.value = response.data.user_id

showSuccessDialog.value = true

// 重置表单

registerData.value = {

mobile: '',

email: '',

nickname: '',

password: '',

passwordConfirm: '',

}

gdprConsent.value = false

} else {

$q.notify({

type: 'negative',

message: response.data.message || '注册失败,请重试',

})

}

} catch (error) {

const axiosError = error as AxiosError

if (axiosError.response) {

const errorData = axiosError.response.data as { [key: string]: string[] } | string

if (typeof errorData === 'string') {

$q.notify({

type: 'negative',

message: errorData,

})

} else {

// 处理字段错误

const errorMessages = Object.values(errorData).flat()

$q.notify({

type: 'negative',

message: errorMessages.join(', ') || '注册失败,请检查输入',

})

}

} else {

$q.notify({

type: 'negative',

message: '网络错误,请检查连接后重试',

})

}

} finally {

isSubmitting.value = false

}

}

</script>

<style lang="scss">

.enterprise-register-card {

max-width: 500px;

margin: 0 auto;

border-radius: 8px;

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

.q-card__section {

padding: 30px;

}

.q-field__label {

font-weight: 500;

}

.q-linear-progress {

height: 8px;

border-radius: 4px;

}

.gdpr-agreement {

font-size: 0.85rem;

margin-top: 10px;

a {

color: var(--q-primary);

text-decoration: none;

&:hover {

text-decoration: underline;

}

}

}

.submit-btn {

height: 48px;

font-size: 1.1rem;

font-weight: 500;

letter-spacing: 0.5px;

border-radius: 6px;

}

}

</style>

四、关键功能说明

1. autocomplete属性优化

所有表单字段均配置符合W3C标准的autocomplete属性,提升浏览器自动填充体验,同时避免敏感信息泄露风险。手机号字段使用tel类型确保移动端唤起数字键盘,密码字段使用new-password提示浏览器禁用旧密码填充。

2. 注册成功跳转机制

通过useRouter实现命名路由跳转,避免硬编码路径带来的维护风险。跳转触发点绑定在成功对话框的确认按钮上,确保用户明确操作意图后再执行跳转,提升体验流畅度。

3. 密码安全增强

实现多维度密码强度评估算法,综合长度、字符多样性、防常用密码等因素,通过颜色编码(红/黄/绿)和文字标签(弱/中/强/非常强)提供直观反馈,引导用户创建高强度密码。

4. 企业级表单验证

采用字段级实时验证策略,结合Quasar的lazy-rules特性优化性能。手机号使用掩码格式化(### #### ####)提升输入体验,同时通过正则表达式确保中国大陆手机号格式正确性。

 

posted on 2025-08-07 21:41  GoGrid  阅读(18)  评论(0)    收藏  举报

导航