当前位置: 首页 > news >正文

vue3项目实战-第六章-登录页(表单校验/模板适配/Pinia管理用户数据/持久化存储)

1、页面搭建与路由配置

在这里,我们要实现的是登录页面,首先,引入静态模板

紧接着,配置路由,因为它是一级路由,直接和Layout并列即可。

{path: '/login',component: Login}

完成之后,浏览器输入login,我们就来到了登录页下面。

2、表单校验

在这里,我们需要考虑一些问题:服务器是怎么知道用户有没有登录的?当用户点击登录的时候,服务器怎么知道用户输入的账号和密码是匹配的?如果用户输入一些乱七八糟的字符,浏览器会给出用户相应的提示吗?给出这些提示的依据是什么?代码应该怎样来编写呢?带着这些问题呢,一起来看看接下来的步骤吧

当用户输入了正确的账号和密码后,浏览器会生成一个令牌字符串Token,它可以用来记录用户当前的登录状态,如果有,说明用户就登陆了,反之,则没有登录,但是前端只能判断token的有无,而token的有效性要交给后端去判断。

那么,我们怎样避免用户输入一些乱七八糟的字符呢?就需要使用一些规则对我们的表单进行校验。通过表单校验,可以省去一些错误的请求提交,为后端节省接口压力。接下来,会详细介绍三种校验方法‘

首先,来看看实现原理

通常情况下,表单校验由三个组件共同完成:

基础步骤如下:

(1)准备表单对象

const form = ref({account: '',password: '',agree: true
})

(2)准备校验规则

const rules = {account: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],password: [{ required: true, message: '密码不能为空', trigger: 'blur' },{ min: 6, max: 14, message: '密码长度为6-14个字符', trigger: 'blur' },],}

(3)指定表单域的校验字段名

<el-form-item prop="account" label="账户"><el-input v-model="form.account" /></el-form-item><el-form-item prop="password" label="密码"><el-input v-model="form.password" /></el-form-item>

(4)把表单对象进行双向绑定

<el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-width="60px" status-icon>

由于ElementPlus内置的表单校验配置只能完成一些基本的校验,如果想要定制一些特定的校验规则,还需要开发者自己来编写相关的逻辑,接下来,看看自定义校验吧

(1)首先,定义一个agree,将其值设为true

agree:true

(2)编写逻辑

 agree: [{validator: (rule, value, callback) => {console.log(value)// 自定义校验逻辑// 勾选就通过 不勾选就不通过if (value) {callback()} else {callback(new Error('请勾选隐私条款和服务条款协议'))}}}]

(3)绑定并使用

<el-form-item prop="agree" label-width="22px"><el-checkbox size="large" v-model="form.agree">我已同意隐私条款和服务条款</el-checkbox></el-form-item>

最后,是表单的统一校验:当用户将表单中所有的内容完成之后,点击登录按钮的时候才会通过校验,发生页面跳转

(1)获取form实例做统一校验

const formRef = ref(null)

(2)绑定

 <el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-wid

运行演示:用户一上来直接点击登录

3、基础功能实现

简单介绍一下实现过程:当用户点击i登录按钮时,需要向服务器发起请求“用户要登录了”,服务器带着这个请求执行登录操作,将用户的信息保存到本地token,如果检测到账号和密码匹配成功的话,将登录结果反馈给用户。接下来,是代码实现

(1)封装登录接口

export const loginAPI = ({ account, password }) => {return request({url: '/login',method: 'POST',data: {account,password}})
}

(2)调用接口,拿到数据(登录之前先对用户输入的内容进行校验,如果校验通过,执行登录操作,反之,提示用户异常信息。)

const doLogin = () => {const { account, password } = form.value// 调用实例方法formRef.value.validate(async (valid) => {// valid: 所有表单都通过校验  才为trueconsole.log(valid)// 以valid做为判断条件 如果通过校验才执行登录逻辑if (valid) {// TODO LOGINawait userStore.getUserInfo({ account, password })// 1. 提示用户ElMessage({ type: 'success', message: '登录成功' })// 2. 跳转首页router.replace({ path: '/' })}})
}

登录成功,跳转到首页,

登录失败,提示错误信息。在本项目中,直接使用测试账号,只要正常复制粘贴,不会出现登录失败的情况。

由于不只有在登录的时候会出现这个问题,其它地方可能也会出现,所以可以把错误处理相关的逻辑封装在响应拦截器里边,

详细如下:

httpInstance.interceptors.response.use(res => res.data, e => {// 统一错误提示ElMessage({type: 'warning',message: e.response.data.message})return Promise.reject(e)
})

保存之后,如果用户输入了错误的用户名或密码,就会提示相应的内容

4、Pinia管理用户数据(持久化)

由于用户数据的特殊性,在很多组件中都有可能进行共享,共享的数据可以使用Pinia来管理,更加方便后续的使用。那么,我们如何使用pinia管理数据?可以把和数据相关的所有操作(state+action)都放到pinia中,组件只负责触发action函数。

核心代码:

(1)定义用户数据

import { defineStore } from 'pinia'
import { ref } from 'vue'
import {loginAPI} from '@/apis/user'
export const useUserStore = defineStore('user', () => {//定义获取用户数据的stateconst userInfo = ref({})//定义获取接口数据的action方法const getUserInfo = async ({ account, password }) => {const res = await loginAPI({ account, password })userInfo.value = res.result}//以对象方式return出去return  {userInfo,getUserInfo}})

(2)在index.vue中引入调用:

1)引入

import {useUserStore} from '@/stores/user'
const userStore = useUserStore()

2)使用

await userStore.getUserInfo({account,password})

这里,由于我们保存的用户数据中有一个叫token的数据,它可以用来标记用户的登录状态,但它有自己的有效期,过一段时间会失效,而Pinia中保存的数据是基于内存的,一旦刷新就会丢失,为了保持登录状态就要做到页面刷新的时候不让用户数据丢失,在这里就需要配合持久化进行存储。

这里,用到了一个新的插件Pinia-plugin-persistedstate,运行机制:在设置state的时候会自动把数据同步给localStorage,在获取state数据的时候会优先从localStorage中取。在使用之前,需要先安装,

npm i pinia-plugin-persistedstate

安装完成之后,配置这样一个属性:

 persist: true,

5、模板适配

未登录状态下,我们看到的效果是

在登录页面,点击右上角进入网站首页,显示如下效果。

而在登录状态下,我们看到的效果是这样的

那么,我们怎样实现这种效果呢?一起来看看吧

在这里,我们可以通过简单的条件渲染来实现

登录状态下

<template v-if="userStore.userInfo.token"><li><a href="javascript:;"><i class=" iconfont icon-user"></i>lyp1234567</a></li><li><el-popconfirm @confirm="confirm" title="确认退出吗?" confirm-button-text="确认" cancel-button-text="取消"><template #reference><a href="javascript:;">退出登录</a></template></el-popconfirm></li><li><a href="/member/order">我的订单</a></li><li><a href="/member">会员中心</a></li></template>

非登录状态下

 <template v-else><li><a href="javascript:;" @click="$router.push('/login')">请先登录</a></li><li><a href="javascript:;">帮助中心</a></li><li><a href="javascript:;">关于我们</a></li></template>

6、请求拦截

当用户点击登录时,首先从Pinia中获取用户数据,如果有的话,根据后端要求将其拼接到Bearer后面

httpInstance.interceptors.request.use(config => {// 1. 从pinia获取token数据const userStore = useUserStore()// 2. 按照后端的要求拼接token数据const token = userStore.userInfo.tokenif (token) {config.headers.Authorization = `Bearer ${token}`}return config
}, e => Promise.reject(e))

7、退出登录

当用户确认退出登录时,需要清空用户数据并跳转到登录页。以下是详细代码:

import { useUserStore } from '@/stores/userStore'
import { useRouter } from 'vue-router'
const userStore = useUserStore()
const router = useRouter()
const confirm = () => {console.log('用户要退出登录了')// 退出登录业务逻辑实现// 1.清除用户信息 触发actionuserStore.clearUserInfo()// 2.跳转到登录页router.push('/login')
}

下期见~

相关文章:

  • 大数据是如何嗅探和捕捉我们的偏好的
  • el-select 选择后获取key 和label的值
  • Wireshare捕获接口中没有本地连接
  • 解决在命令行中输入py有效,输入python无效,输入python会跳转到microsoft store的问题| Bug
  • wayland(xdg_wm_base) + egl + opengles 渲染使用纹理贴图的旋转 3D 立方体实例(十三)
  • JavaSE(上)-Day7
  • 什么是委托,委托的本质是什么?
  • 爱奇艺 CTR 场景下的 GPU 推理性能优化
  • LeetCode 热题100 链表专题解析
  • ElasticSearch第二章(ES8.X的使用)
  • jvm的垃圾回收器以及触发full gc的场景
  • 概率基础——逻辑回归多分类法
  • git 安装、创建仓库、常用命令、克隆下载、上传项目、删除分支 -- 一篇文章总结
  • Lua中文语言编程源码-第二节,更改lbaselib.c基础库模块, 使Lua支持中文关键词(与操作相关的)
  • [论文精读]Dynamic Coarse-to-Fine Learning for Oriented Tiny Object Detection
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • JavaScript 如何正确处理 Unicode 编码问题!
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • IDEA 插件开发入门教程
  • java概述
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • JS基础之数据类型、对象、原型、原型链、继承
  • JWT究竟是什么呢?
  • MaxCompute访问TableStore(OTS) 数据
  • php面试题 汇集2
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 后端_MYSQL
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • ------- 计算机网络基础
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 怎样选择前端框架
  • 自动记录MySQL慢查询快照脚本
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #pragma 指令
  • (2)(2.10) LTM telemetry
  • (HAL库版)freeRTOS移植STMF103
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转载)Google Chrome调试JS
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面
  • /var/spool/postfix/maildrop 下有大量文件
  • @Transactional 详解
  • @Validated和@Valid校验参数区别
  • @拔赤:Web前端开发十日谈
  • [ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证
  • [1204 寻找子串位置] 解题报告
  • [acwing周赛复盘] 第 69 场周赛20220917
  • [Android] 240204批量生成联系人,短信,通话记录的APK