黑马头条vue2.0项目实战(二)——登录注册功能的实现

1. 布局结构

目标

  • 能实现登录页面的布局

  • 能实现基本登录功能

  • 能掌握 Vant 中 Toast 提示组件的使用

  • 能理解 API 请求模块的封装

  • 能理解发送验证码的实现思路

  • 能理解 Vant Form 实现表单验证的使用

这里主要使用到三个 Vant 组件:

  • NavBar 导航栏

  • Form 表单

    • Field 输入框

    • Button 按钮

1.1 布局样式

        写样式的原则:将公共样式写到全局(src/styles/index.less),将局部样式写到组件内部。对于需要更改样式,自己添加 class 类名。

1.2 自定义图标的使用

官方文档实现:

实现效果:

最左侧显示的图标无法满足需求的情况下,可以通过 slot 实现,插入自定义的图标。可以插入的slot如下所示:

具体实现,通过插入 i 标签,设置 iconfont 类名。

1.2 插入按钮

官方文档:

实现效果:

        但是在表单中,除了提交按钮外,可能还有一些其他的功能性按钮,如发送验证码按钮。在使用这些按钮时,要注意将 native-type设置为button,否则会触发表单提交。

2. 实现基本登录功能

功能需求:

  • 注册点击登录的事件

  • 获取表单数据(根据接口要求使用 v-model 绑定)

  • 表单验证

  • 发请求提交

  • 根据请求结果做下一步处理

2.1 登录状态提示

2.2 表单验证

  •  给 vant-field 组件配置 rules 验证规则     

  • 可以在 data 里自定义校验规则校验手机号和验证码

  • 当给表单提交的时候会自动触发表单验证
    • 如果验证通过,则触发 submit 事件
    • 如果验证不通过,则不会触发 submit 事件
    • 验证规则 参考vant组件的文档

2.3 验证码处理

点击发送验证码功能

功能需求:

  • 点击发送验证码按钮后,对用户输入的手机号进行验证

  • 验证通过显示倒计时

  • 发送用户手机号给后端,后台给用户手机下发验证码
  • 发送失败关闭倒计时

注意:

  • 这里的 ref 是绑在表单 Form上
  • 获取表单实例之后,通过 .validate('校验表单或输入框的name属性值')
  • 返回的是一个 promise 对象

3. 处理用户 Token

Token 是用户登录成功之后服务端返回的一个身份令牌,在项目中的多个业务中需要使用到:

  • 访问需要授权的 API 接口

  • 校验页面的访问权限

  • ...

但是我们只有在第一次用户登录成功之后才能拿到 Token。

所以为了能在其它模块中获取到 Token 数据,我们需要把它存储到一个公共的位置,方便随时取用。

往哪儿存?

  • 本地存储

    • 获取麻烦

    • 数据不是响应式

  • Vuex 容器(推荐)

    • 获取方便

    • 响应式的

3.1 使用容器存储 Token 的思路

  • 登录成功,将 Token 存储到 Vuex 容器中

    • 获取方便

    • 响应式

  • 为了持久化,还需要把 Token 放到本地存储

    • 持久化

登录成功以后将后端返回的 token 相关数据存储到容器中

3.2 优化封装本地存储操作模块

创建 src/utils/storage.js 模块

3.3 关于 Token 过期问题

登录成功之后后端会返回两个 Token:

  • token:访问令牌,有效期2小时

  • refresh_token:刷新令牌,有效期14天,用于访问令牌过期之后重新获取新的访问令牌

我们的项目接口中设定的 Token 有效期是 2 小时,超过有效期服务端会返回 401 表示 Token 无效或过期了。

为什么过期时间这么短?

  • 为了安全,例如 Token 被别人盗用

过期了怎么办?

  • 让用户重新登录,用户体验太差了

  • 使用 refresh_token 解决 token 过期

后续拓展 Token 过期处理 ,在学习测试的时候如果收到 401 响应码,请重新登录再测试

概述:服务器生成token的过程中,会有两个时间,一个是token失效时间,一个是token刷新时间,刷新时间肯定比失效时间长,当用户的 token 过期时,你可以拿着过期的token去换取新的token,来保持用户的登陆状态,当然你这个过期token的过期时间必须在刷新时间之内,如果超出了刷新时间,那么返回的依旧是 401。

处理流程:

  1. 在axios的拦截器中加入token刷新逻辑

  2. 当用户token过期时,去向服务器请求新的 token

  3. 把旧的token替换为新的token

  4. 然后继续用户当前的请求

在请求的响应拦截器中统一处理 token 过期(后续拓展)。

/*** 封装 axios 请求模块*/
import axios from "axios";
import jsonBig from "json-bigint";
import store from "@/store";
import router from "@/router";// axios.create 方法:复制一个 axios
const request = axios.create({baseURL: "http://ttapi.research.itcast.cn/" // 基础路径
});/*** 配置处理后端返回数据中超出 js 安全整数范围问题*/
request.defaults.transformResponse = [function(data) {try {return jsonBig.parse(data);} catch (err) {return {};}}
];// 请求拦截器
request.interceptors.request.use(function(config) {const user = store.state.user;if (user) {config.headers.Authorization = `Bearer ${user.token}`;}// Do something before request is sentreturn config;},function(error) {// Do something with request errorreturn Promise.reject(error);}
);// 响应拦截器
request.interceptors.response.use(// 响应成功进入第1个函数// 该函数的参数是响应对象function(response) {// Any status code that lie within the range of 2xx cause this function to trigger// Do something with response datareturn response;},// 响应失败进入第2个函数,该函数的参数是错误对象async function(error) {// Any status codes that falls outside the range of 2xx cause this function to trigger// Do something with response error// 如果响应码是 401 ,则请求获取新的 token// 响应拦截器中的 error 就是那个响应的错误对象console.dir(error);if (error.response && error.response.status === 401) {// 校验是否有 refresh_tokenconst user = store.state.user;if (!user || !user.refresh_token) {router.push("/login");// 代码不要往后执行了return;}// 如果有refresh_token,则请求获取新的 tokentry {const res = await axios({method: "PUT",url: "http://ttapi.research.itcast.cn/app/v1_0/authorizations",headers: {Authorization: `Bearer ${user.refresh_token}`}});// 如果获取成功,则把新的 token 更新到容器中console.log("刷新 token  成功", res);store.commit("setUser", {token: res.data.data.token, // 最新获取的可用 tokenrefresh_token: user.refresh_token // 还是原来的 refresh_token});// 把之前失败的用户请求继续发出去// config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有// return 把 request 的请求结果继续返回给发请求的具体位置return request(error.config);} catch (err) {// 如果获取失败,直接跳转 登录页console.log("请求刷新 token 失败", err);router.push("/login");}}return Promise.reject(error);}
);export default request;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/385650.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux文件恢复

很麻烦 一般还是小心最好 特别恢复的时候 可能不能选择某个文件夹去扫描恢复 所以 删除的时候 用rm -i代替rm 一定小心 以及 探索下linux的垃圾箱机制 注意 一定要恢复到不同文件夹 省的出问题 法1 系统自带工具 debugfs 但是好像不能重启? testdisk 1、安装 …

C++项目——高并发内存池

一、什么是内存池 内存池(Memory Pool) 是一种动态内存分配与管理技术。 通常情况下,程序员习惯直接使用new、delete、malloc、free 等API申请分配和释放内存,这样导致的后果是:当程序长时间运行时,由于所申请内存块的大小不定&…

OpenCV 图像预处理—图像金字塔

文章目录 相关概念高斯金字塔拉普拉斯金字塔应用 构建高斯金字塔为什么要对当前层进行模糊?1. 平滑处理2. 减少混叠(Aliasing)3. 多尺度表示4. 图像降采样 举个栗子创建高斯金字塔和拉普拉斯金字塔,并用拉普拉斯金字塔恢复图像 相…

【VUE】个人记录:父子页面数据传递

1. 父传子 在父页面中&#xff0c;调用子页面的组件位置处&#xff0c;通过“&#xff1a;”进行参数传递 <child-component :childData"parentData"></child-component>parentData对象&#xff0c;需要在父页面的data中进行初始化声明 在子页面中&am…

百易云资产管理运营系统 comfileup.php 文件上传致RCE漏洞复现(XVE-2024-18154)

0x01 产品简介 百易云资产管理运营系统,是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理,包括资产的登记、盘点、评估、处置等多个环节,同时提供强大的运营分析功能,帮助企业优化资产配置,提升运营效率。 0x02 漏…

为RTEMS Raspberrypi4 BSP添加SPI支持

为RTEMS Raspberrypi4 BSP添加SPI支持 主要参考了dev/bsps/shared/dev/spi/cadence-spi.c RTEMS 使用了基于linux的SPI框架&#xff0c;SPI总线驱动已经在内核中实现。在这个项目中我需要实习的是 RPI4的SPI主机控制器驱动 SPI在RTEMS中的实现如图&#xff1a; 首先需要将S…

Profinet从站转TCP/IP协议转化网关(功能与配置)

如何将Profinet和TCP/IP网络连接通讯起来呢?近来几天有几个朋友问到这个问题&#xff0c;那么作者在这里统一说明一下。其实有一个不错的设备产品可以很轻易地解决这个问题&#xff0c;名为JM-DNT-PN。接下来作者就从该设备的功能及配置详细说明一下。 一&#xff0c;设备主要…

Python:随机数、随机选择的应用

step1:导入 导入的random相当于是创建了random文件里的的一个对象 import random random() 产生0~1随机数 randint(a,b)产生a~b的整数 闭区间&#xff0c;可以取到a,b random.choice(touple_name)从touple_name&#xff08;数组、列表..&#xff09;中随机选择元素 import rand…

JSP内置对象及作用域

Request 存东西ResponseSession 存东西Application [ SerlvetContext ] 存东西config [ SerlvetConfig ]out/targetpage 不用了解exception <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head><title>…

DBeaver使用SQL脚本编辑器

文章目录 1 新建脚本2 选择数据库3 编写脚本【按行执行】参考 1 新建脚本 2 选择数据库 3 编写脚本【按行执行】 光标放到需要执行的行上&#xff0c;点击【最上面的按钮】 或者选中某片代码&#xff0c;然后执行 也可以编写一个脚本然后执行 参考 dbeaver安装和使用教程 …

LeetCode 热题 HOT 100 (011/100)【宇宙最简单版】

【图论】No. 0200 岛屿数量 【中等】&#x1f449;力扣对应题目指路 希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#xf…

Chrome谷歌浏览器Console(控制台)显示文件名及行数

有没有这样的困扰&#xff1f;Chrome谷歌浏览器console(控制台)不显示编译文件名及行数? 设置&#xff08;Settings&#xff09;- > 忽略列表&#xff08;lgnore List&#xff09;-> 自定义排除规则&#xff08;Custom exclusion rules&#xff09; 将自定义排除规则…

Skyeye云智能制造企业版源代码全部开放

智能制造一体化管理系统 [SpringBoot2 - 快速开发平台]&#xff0c;适用于制造业、建筑业、汽车行业、互联网、教育、政府机关等机构的管理。包含文件在线操作、工作日志、多班次考勤、CRM、ERP 进销存、项目管理、EHR、拖拽式生成问卷、日程、笔记、工作计划、行政办公、薪资模…

【数据结构】堆,优先级队列

目录 堆堆的性质大根堆的模拟实现接口实现构造方法建堆入堆判满删除判空获取堆顶元素 Java中的PriorityQueue实现的接口构造方法常用方法PriorityQueue注意事项 练习 堆 如果有一个集合K {k0&#xff0c;k1&#xff0c; k2&#xff0c;…&#xff0c;kn-1}&#xff0c;把它的…

【C++】C++入门基础

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C 个人主页&#xff1a;Celias blog~ 目录 一、C简介 二、第一个C程序 三、namespace 命名空间 3.1 na…

UART 通信协议

文章目录 一 简介二 电平标准三 引脚定义四 数据格式五 波特率 一 简介 ​ UART (Universal Asynchronous Receiver/Transmitter)&#xff0c;通用异步收发器&#xff0c;是一种串行、异步、全双工通信协议。 串行&#xff1a;利用一条传输线&#xff0c;将数据一位一位地传送…

一整套开箱即用的前端管理后台解决方案,基于 Vue.js搭配使用 iView UI 组件库形成的,私活神器

前言 在现代Web应用开发中&#xff0c;后台管理系统的构建常常面临诸多挑战&#xff0c;如复杂的权限管理、多语言支持、响应式设计等。现有解-决方案可能存在功能不丰富、定制难度大、开发效率低等问题。 为了解决这些痛点&#xff0c;一款新的软件——iView Admin&#xff…

【Docker】Windows11环境下的安装

前置依赖环境配置 确保虚拟化开启 搜索栏直接搜索如下功能 勾选下面两个选项&#xff0c;确定 重启电脑&#xff0c;以管理员身份打开PowerShell wsl --status wsl --update打开微软应用商店选择一个Ubuntu版本下载并打开 输入一个用户名和密码 然后就可以在Windows下使…

Flink-CDC解析(第47天)

前言 本文主要概述了Flink-CDC. 1. CDC 概述 1.1 什么是CDC&#xff1f; CDC是&#xff08;Change Data Capture 变更数据获取&#xff09;的简称 &#xff0c;在广义的概念上&#xff0c;只要是能捕获数据变更的技术&#xff0c;都可以称之为 CDC。 核心思想是&#xff0c…

昇思MindSpore 应用学习-GAN图像生成-CSDN

模型简介 生成式对抗网络(Generative Adversarial Networks&#xff0c;GAN)是一种生成式机器学习模型&#xff0c;是近年来复杂分布上无监督学习最具前景的方法之一。 最初&#xff0c;GAN由Ian J. Goodfellow于2014年发明&#xff0c;并在论文Generative Adversarial Nets中…