04-简单注册和登录
分类: Java springboot vue 专栏: 【带小白做项目】springboot和vue前台开发 标签: 注册登录
2025-10-22 19:16:49 90浏览
前提
先看后台开发的教程
https://www.bilibili.com/video/BV1JbUXYyEdx
因为是在这个的基础上开发前台
用到的工具
先用这个粗略的画一个 vue 页面
然后自己改造,把死的页面动起来,交互起来,也就是要发请求。
美化页面啥的,或者遇到 bug 可以借助 ai 插件——codegeex
最终效果


几个请求
以下三个接口,杰哥偷懒了,直接共用了之前后台的登录注册
1. 登录接口
username:账号
password:密码
userType:user
2. 注册接口
username:账号
password:密码
rawPassword:确认密码
3. 验证账号唯一性的接口
这个接口要注意异步请求。可能会出现的 bug,

我这里明明写的是数据库存在的一个账号,并且失去焦点的时候已经能正常提示出账号已存在的错误信息,但我就是不管,直接点注册。导致竟然注册成功了,这显然不合理。



核心代码
<template>
<div>
<heard-view/>
<div class="auth-container">
<div class="auth-card">
<div class="auth-header">
<h2>{{ isLogin ? '登录' : '注册' }}</h2>
<p>{{ isLogin ? '欢迎回来!' : '创建新账户' }}</p>
</div>
<form @submit.prevent="handleSubmit" class="auth-form">
<!-- 账号输入 -->
<div class="form-group">
<label for="username">账号</label>
<input
id="username"
v-model="form.username"
type="text"
placeholder="请输入账号"
:class="{ 'error': errors.username }"
@blur="validateUsername"
/>
<span v-if="errors.username" class="error-message">{{ errors.username }}</span>
</div>
<!-- 密码输入 -->
<div class="form-group">
<label for="password">密码</label>
<div class="password-input">
<input
id="password"
v-model="form.password"
:type="showPassword ? 'text' : 'password'"
placeholder="请输入密码"
:class="{ 'error': errors.password }"
@blur="validatePassword"
/>
<button
type="button"
class="toggle-password"
@click="showPassword = !showPassword"
>
{{ showPassword ? '隐藏' : '显示' }}
</button>
</div>
<span v-if="errors.password" class="error-message">{{ errors.password }}</span>
</div>
<!-- 确认密码(仅注册时显示) -->
<div v-if="!isLogin" class="form-group">
<label for="rawPassword">确认密码</label>
<input
id="rawPassword"
v-model="form.rawPassword"
type="password"
placeholder="请再次输入密码"
:class="{ 'error': errors.rawPassword }"
@blur="validaterawPassword"
/>
<span v-if="errors.rawPassword" class="error-message">{{ errors.rawPassword }}</span>
</div>
<!-- 提交按钮 -->
<button
type="submit"
class="submit-btn"
:disabled="isSubmitting"
>
{{ isSubmitting ? '处理中...' : (isLogin ? '登录' : '注册') }}
</button>
<!-- 切换登录/注册 -->
<div class="switch-auth">
<span>{{ isLogin ? '还没有账户?' : '已有账户?' }}</span>
<button
type="button"
class="switch-btn"
@click="toggleAuthMode"
>
{{ isLogin ? '立即注册' : '立即登录' }}
</button>
</div>
</form>
</div>
</div>
<foot-view/>
</div>
</template>
<script>
import heardView from "@/views/front/HeardView.vue";
import footView from "@/views/front/FootView.vue";
import {checkUsername, loginApi, regUser} from "@/api/app";
// import axios from "axios";
export default {
name: 'AuthComponent',
components: {footView, heardView},
data() {
return {
isLogin: true,
showPassword: false,
isSubmitting: false,
form: {
username: '',
password: '',
userType: 'user',
rawPassword: ''
},
errors: {
username: '',
password: '',
rawPassword: ''
},
}
},
methods: {
// 切换登录/注册模式
toggleAuthMode() {
this.isLogin = !this.isLogin
this.resetForm()
this.clearErrors()
},
// 重置表单
resetForm() {
this.form = {
username: '',
password: '',
rawPassword: '',
userType: 'user'
}
},
// 清除错误信息
clearErrors() {
this.errors = {
username: '',
password: '',
rawPassword: ''
}
},
// 验证用户名
async validateUsername() {
if (!this.form.username.trim()) {
this.errors.username = '账号不能为空'
return false
}
if (this.form.username.length < 3) {
this.errors.username = '账号长度至少3个字符'
return false
}
if (!/^[a-zA-Z0-9_]+$/.test(this.form.username)) {
this.errors.username = '账号只能包含字母、数字和下划线'
return false
}
// 注册时检查用户名唯一性
if (!this.isLogin) {
// const res=await axios.get(`/dev-api/user/check/${this.form.username}`)
const res=await checkUsername(this.form.username)
console.log(res)
this.errors.username = ''
return true
} else {
//登录
this.errors.username = ''
return true
}
},
// 验证密码
validatePassword() {
if (!this.form.password) {
this.errors.password = '密码不能为空'
return false
}
if (this.form.password.length < 6) {
this.errors.password = '密码长度至少6个字符'
return false
}
if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(this.form.password)) {
this.errors.password = '密码必须包含字母和数字'
return false
}
this.errors.password = ''
return true
},
// 验证确认密码
validaterawPassword() {
if (!this.form.rawPassword) {
this.errors.rawPassword = '请确认密码'
return false
}
if (this.form.password !== this.form.rawPassword) {
this.errors.rawPassword = '两次输入的密码不一致'
return false
}
this.errors.rawPassword = ''
return true
},
// 验证整个表单
async validateForm() {
const isUsernameValid = await this.validateUsername()
const isPasswordValid = this.validatePassword()
if (!this.isLogin) {
const israwPasswordValid = this.validaterawPassword()
console.log(isUsernameValid)
console.log(israwPasswordValid)
console.log(isPasswordValid)
return isUsernameValid && isPasswordValid && israwPasswordValid
}
return isUsernameValid && isPasswordValid
},
// 提交表单
async handleSubmit() {
const isValid = await this.validateForm()
console.log('表单验证结果:', isValid)
if (!isValid) {
return
}
this.isSubmitting = true
try {
if (this.isLogin) {
loginApi(this.form).then(res =>{
console.log(res)
this.$message.success('登录成功')
sessionStorage.setItem("token", res.data);
sessionStorage.setItem("username", this.form.username);
sessionStorage.setItem("role", this.form.userType);
this.$router.push("/index")
})
} else {
regUser(this.form).then(res =>{
console.log(res)
this.$message.success('注册成功')
this.toggleAuthMode()
})
}
} catch (error) {
console.error('操作失败:', error)
alert('操作失败,请重试')
} finally {
this.isSubmitting = false
}
}
}
}
</script>
<style scoped>
.auth-container {
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 60px);
padding-top: 60px; /* 导航栏高度 */
background-color: #f5f7fa;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
}
.auth-card {
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 400px;
margin-bottom: 40px;
transition: all 0.3s ease;
}
.auth-card:hover {
box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.auth-header {
text-align: center;
margin-bottom: 30px;
position: relative;
}
.auth-header h2 {
color: #303133;
margin-bottom: 12px;
font-size: 24px;
font-weight: bold;
}
.auth-header p {
color: #909399;
font-size: 14px;
}
.auth-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-group label {
margin-bottom: 8px;
color: #606266;
font-weight: 500;
font-size: 14px;
}
.form-group input {
padding: 12px 15px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
transition: all 0.3s;
height: 40px;
line-height: 1;
box-sizing: border-box;
}
.form-group input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
.form-group input:hover {
border-color: #c0c4cc;
}
.form-group input.error {
border-color: #f56c6c;
}
.password-input {
position: relative;
}
.toggle-password {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: #909399;
cursor: pointer;
font-size: 14px;
padding: 0;
}
.toggle-password:hover {
color: #409eff;
}
.error-message {
color: #f56c6c;
font-size: 12px;
margin-top: 6px;
line-height: 1;
}
.submit-btn {
background-color: #409eff;
color: white;
border: none;
padding: 12px 20px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
margin-top: 10px;
}
.submit-btn:hover:not(:disabled) {
background-color: #66b1ff;
}
.submit-btn:active:not(:disabled) {
background-color: #3a8ee6;
}
.submit-btn:disabled {
background-color: #a0cfff;
cursor: not-allowed;
}
.switch-auth {
text-align: center;
margin-top: 20px;
font-size: 14px;
}
.switch-auth span {
color: #606266;
}
.switch-btn {
background: none;
border: none;
color: #409eff;
cursor: pointer;
font-size: 14px;
margin-left: 5px;
padding: 0;
}
.switch-btn:hover {
color: #66b1ff;
}
/* 响应式设计 */
@media (max-width: 768px) {
.auth-container {
padding: 20px;
}
.auth-card {
padding: 30px 20px;
}
}
</style>
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论



新业务
springboot学习
ssm框架课
vue学习
【带小白】java基础速成