Vue 3 项目实战教程:大事件管理系统(二)——路由设计与注册登录功能
1.整体路由设计


路由约定规则:
| path | 文件 | 功能 | 组件名 | 路由级别 |
|---|---|---|---|---|
| /login | views/login/LoginPage.vue | 登录&注册 | LoginPage | 一级路由 |
| / | views/layout/LayoutContainer.vue | 布局架子 | LayoutContainer | 一级路由 |
| ├─ /article/manage | views/article/ArticleManage.vue | 文章管理 | ArticleManage | 二级路由 |
| ├─ /article/channel | views/article/ArticleChannel.vue | 频道管理 | ArticleChannel | 二级路由 |
| ├─ /user/profile | views/user/UserProfile.vue | 个人详情 | UserProfile | 二级路由 |
| ├─ /user/avatar | views/user/UserAvatar.vue | 更换头像 | UserAvatar | 二级路由 |
| ├─ /user/password | views/user/UserPassword.vue | 重置密码 | UserPassword | 二级路由 |
标准工作流程:Vue 路由开发步骤(含二级路由)
1.创建页面文件夹和 .vue 文件
2.在 router/index.js 中配置路由规则
import { createRouter, createWebHistory } from 'vue-router'
//createRouter创建路由实例
//配置 history 模式: createWebHistory 地址栏不带#
//配置 hash 模式: createHashHistory 地址栏带#
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{path:'/login',component:()=>import('../views/login/LoginPage.vue')}, //登入页
{
path:'/',component:()=>import('../views/layout/LayoutContainer.vue'), //一旦访问了这个路径,需要重定向第一个文章组件 文章管理
redirect:'/article/manage', //接下来配置他的二级路由
children :[
{path:'/article/manage',component:()=>import('../views/article/ArticleManage.vue')},
{path:'/article/channel',component:()=>import('../views/article/ArticleChannel.vue')},
{path:'/article/profile',component:()=>import('../views/user/UserProfile.vue')},
{path:'/article/avatar',component:()=>import('../views/user/UserAvatar.vue')},
{path:'/article/password',component:()=>import('../views/user/UserPassword.vue')},
]
},
]
})
export default router
3.在 App.vue 中写一级路由出口
<hr/>
<hr/>
<hr/>
<router-view></router-view>
<hr/>
<hr/>
<hr/>
<hr/>
4.在 LayoutContainer.vue 中写二级路由出口
<template>
<div>
布局架子
<router-view></router-view>
</div>
</template>
测试:


2.注册登入界面-静态结构
利用 element-ui 的栅格系统布局
使用前记得安装element-ui图标库
install @element-plus/icons-vue
布局这里用了官方文档中的基本布局和列偏移
https://element-plus.org/zh-CN/component/layout.html

<script setup>
import { User, Lock } from '@element-plus/icons-vue'
import { ref } from 'vue'
const isRegister = ref(true)
</script>
<template>
<el-row class="login-page">
<el-col :span="12" class="bg"></el-col>
<el-col :span="6" :offset="3" class="form">
<!-- 这是注册表单 -->
<el-form size="large" autocomplete="off" v-if="isRegister">
<el-form-item>
<h1>注册</h1>
</el-form-item>
<el-form-item>
<el-input :prefix-icon="User" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item>
<el-input
:prefix-icon="Lock"
type="password"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item>
<el-input
:prefix-icon="Lock"
type="password"
placeholder="请输入再次密码"
></el-input>
</el-form-item>
<el-form-item>
<el-button class="button" type="primary" auto-insert-space>
注册
</el-button>
</el-form-item>
<el-form-item class="flex">
<el-link type="info" :underline="false" @click="isRegister = false">
← 返回
</el-link>
</el-form-item>
</el-form>
<!-- 这是登入表单 -->
<el-form size="large" autocomplete="off" v-else>
<el-form-item>
<h1>登录</h1>
</el-form-item>
<el-form-item>
<el-input :prefix-icon="User" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item>
<el-input
name="password"
:prefix-icon="Lock"
type="password"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item class="flex">
<div class="flex">
<el-checkbox>记住我</el-checkbox>
<el-link type="primary" :underline="false">忘记密码?</el-link>
</div>
</el-form-item>
<el-form-item>
<el-button class="button" type="primary" auto-insert-space
>登录</el-button
>
</el-form-item>
<el-form-item class="flex">
<el-link type="info" :underline="false" @click="isRegister = true">
注册 →
</el-link>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
.login-page {
height: 100vh;
background-color: #fff;
.bg {
background: url('@/assets/logo2.png') no-repeat 60% center / 240px auto,
url('@/assets/login_bg.jpg') no-repeat center / cover;
border-radius: 0 20px 20px 0;
}
.form {
display: flex;
flex-direction: column;
justify-content: center;
user-select: none;
.title {
margin: 0 auto;
}
.button {
width: 100%;
}
.flex {
width: 100%;
display: flex;
justify-content: space-between;
}
}
}
</style>
代码讲解:
el-row下面分两个 el-col,分别占一半用:span="12"控制
写表单的位置放入了两个表单,一个注册表单,一个登入表单,用v-if控制,写一个bool变量,假设如果是true就是注册表单,如果是false就是登入表单,用按钮改变bool值
<el-col :span="12" class="bg"></el-col> 绑定了背景图片,看下面的 css
<el-col :span="6" :offset="3" class="form">中间放表单</el-col>
这个意思是列偏移3个单位,本身占 6 个单位大小 ,绑定了一个 form 类,是自己定义的,用来调整表格居中
表单最外层是el-form,每一个小部分都是el-form-item,每一个el-form-item或者el-button或者el-link
<el-form size="large" autocomplete="off" v-if="isRegister">
1.size是element-ui带的,调整表单大小的
2.autocomplete是html带的,阻止浏览器填充历史数据
<el-input
:prefix-icon="Lock"
type="password"
placeholder="请输入密码"
></el-input>
1.:prefix-icon 绑定element-ui带的图标库
2. type element-ui带的类型,password表示密码框,有一个 show-password控制他是否显示密码
3. placeholder默认文字 input自带的
3.表单校验
使用下面的四个参数,即可完成表单校验
去官方文档中找表单校验
- :model 绑定的是整个 form 的数据对象{XXX,XXX,XXX},我们自行定义form 的数据对象
- :rules 绑定的整个 rules 的规则对象,同样可以去自行找组件库,自行定义,也可以用自定义规则
- 表单元素绑定 v-model 双向数据绑定,将自行定义form 的数据对象绑定到对应的表单元素上
- prop 绑定的是校验规则,跟 rules 中的字段对应上
注意四个参数都往哪里配

实例如下:
1.定义form 的数据对象
2.定义规则
3.往代码里加
规则说明:
- required:true 表示是否非空
- message: 提示的消息
- trigger 表示触发的方式,这个 blur 是失去焦点,还有 change
这种定义的规则可以直接看官网上看,拿来用
效果如下:
表单校验规则:
- 非空校验
- 长度检验 min:xx max:xx
- 正则校验 pattern:正则逻辑 \S 非空字符
- 自定义校验 自己写逻辑(校验函数)
如何自定义校验规则?
自定义校验函数解释:
validator:(rule,value,callback)
- rule 当前校验规则相关信息
- value 当前表单中的表单值
- callback 无论校验是否成功 都需要 callback 回调
- callback() 校验成功
- callback (new Error(错误信息)) 校验失败
代码如下:
// 2.定义规则
const rules={
username:[
{required: true, message: '请输入用户名', trigger: 'blur'},
{min:5,max:10,message: '用户名必须是 5-10 位的字符', trigger: 'blur'}
],
password:[
{required: true, message: '请输入密码', trigger: 'blur'},
{ pattern: /^\S{6,15}$/,
message:'密码必须 6-15 位的非空字符',
trigger:'blur'
}
],
repassword:[
{required: true, message: '请输入密码', trigger: 'blur'},
{ pattern: /^\S{6,15}$/,
message:'密码必须 6-15 位的非空字符',
trigger:'blur'
},
{
validator:(rule,value,callback)=>{
//盘点 value和当前 form 中收集的 password 是否一致
if(value!==formModel.value.password)
{
callback(new Error('两次输入密码不一致'))
} else{
callback() //校验成功,也要 callback
}
}
}
],
}
完整校验后效果如下:
4.注册预检验及注册页面
点击注册按钮,注册之前,需要先校验一下,比如表单提交的数据不能为空
使用的是 element-ui 暴露出来的方法,通过 ref 拿到表单对象之后就可以直接使用表达暴露出来的方法
这个方法会去检查你在 rules 中定义的每一项规则(比如 required、正则等),一旦发现某项不符合,它就会:自动在输入框下方提示错误信息(这是它内部自己处理的 UI 行为)同时并且这个 validate() 方法会 抛出一个错误,导致 await 报错
const form =ref()
const register=async()=>{
//注册成功之前,先进行校验,校验成功之后->请求,校验失败->自动提示
await form.value.validate()
console.log('开始注册请求')
}
<el-button class="button" type="primary" auto-insert-space @click="register">
注册
</el-button>

看接口文档
在 api 下面创建一个 user.js 的文件,封装请求数据 的方法
import request from '@/utils/request'
export const userRegisterService=({username,password,repassword})=>{
return request.post('/api/reg',{username,password,repassword})
}
将 api 中写好的方法放入.vue 文件中,使用,改写注册点击事件
import {userRegisterService} from '@/api/user.js'
const register=async()=>{
//注册成功之前,先进行校验,校验成功之后->请求,校验失败->自动提示
await form.value.validate()
//传入一个对象
await userRegisterService(formModel.value)
alert('注册成功')
console.log('开始注册请求')
}
修改注册成功的样式,将 alert 换成 element-ui 的组件
用法:
ElMessage.success('注册成功')
5.登入界面
对登入表单进行一些类绑定
校验规则,直接用之前注册页面写的
在写完之后存在一个 bug,在切换登入界面和注册界面,表单数据没有消失,登入界面的用户名,你在注册页面可能看到,切换的时候,应该重置表单内容.
使用侦听器处理,通过侦听 isRegister
//切换的时候,重置表单内容
watch(isRegister,()=>{
formModel.value={
username:'',
password:'',
repassword:''
}
})
根据接口文档写 api
const login=async()=>{
//注册成功之前,先进行校验,校验成功之后->请求,校验失败->自动提示
await form.value.validate()
// 传入一个对象,拿到传回的值,里面含有 token 需要拿到里面去,存到 store 里
const res= await userLoginService(formModel.value)
ElMessage.success('登入成功')
console.log(res)
}
console.log内容如下:
将 token 值存入到 store 中:
import {useUserStore} from '@/stores'
const userStore =useUserStore()
userStore.setToken(res.data.token)

登入成功之后跳转路由:
import {useRouter} from 'vue-router'
const router =useRouter()
router.push('/')

更多推荐



所有评论(0)