vue实战——登录【详解】(含自适配全屏背景,记住账号--支持多账号,显隐密码切换,登录状态保持)

本文主要是介绍vue实战——登录【详解】(含自适配全屏背景,记住账号--支持多账号,显隐密码切换,登录状态保持),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果预览

在这里插入图片描述

技术要点——自适配全屏背景

https://blog.csdn.net/weixin_41192489/article/details/119992992

技术要点——密码输入框

自定义图标切换显示隐藏
https://blog.csdn.net/weixin_41192489/article/details/133940676

技术要点——记住账号(支持多账号)

核心需求和逻辑

  • 勾选“记住账号”,一旦登录成功过,下次登录能在账号输入框的输入推荐建议列表中,选择该账号

在这里插入图片描述

  • 未勾选“记住账号”,登录成功后,清除对该账号的存储

相关代码

页面加载时,获取记住的账号

  mounted() {this.accountList = JSON.parse(localStorage.getItem("accountList")) || [];},

使用带输入建议的输入框

          <el-autocompleteclearableclass="inputStyle"v-model="formData.account":fetch-suggestions="queryAccount"placeholder="请输入账号"@select="chooseAccount"></el-autocomplete>

根据输入内容,从记住的账号中,过滤出最接近的已记住的账号

    queryAccount(queryString, cb) {let accountList = JSON.parse(JSON.stringify(this.accountList));accountList = accountList.map((item) => {return {value: item,};});var results = queryString? accountList.filter(this.createFilter(queryString)): accountList;cb(results);},createFilter(queryString) {return (restaurant) => {return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) ===0);};},

根据输入建议下拉选择中,选择已记住的账号时,自动勾选记住账号,并清空表单校验

    chooseAccount(newAccount) {if (this.accountList.includes(newAccount.value)) {this.remember = true;}this.$nextTick(() => {this.$refs.formRef.clearValidate();});},

登录成功后,根据是否勾选记住账号,存入新账号或移除已记住的账号。

                this.$message({offset: 150,message: "登录成功!",type: "success",});let account = this.formData.account;// 勾选-记住账号if (this.remember) {// 没记住过if (!this.accountList.includes(account)) {// 存入localStoragethis.accountList.push(account);localStorage.setItem("accountList",JSON.stringify(this.accountList));}} else {// 未勾选-记住账号removeItem(this.accountList, account);localStorage.setItem("accountList",JSON.stringify(this.accountList));}

用到的工具函数

// 普通数组移除指定元素
function removeItem(arr, item) {let targetIndex = arr.findIndex((itemTemp) => itemTemp === item);if (targetIndex !== -1) {arr.splice(targetIndex, 1);}
}

技术要点——登录后维持登录状态

this.$store.commit("set_token", res.data.data.token);
this.$store.commit("set_isLogin", true);
this.$store.commit("set_userInfo", res.data.data);

完整范例代码

<template><div class="bg loginPage"><div><div><div class="hello">Hi,你好!</div><div class="hello2">欢迎进入观光车调度系统</div></div><div class="logoBox"><imgclass="logoBox"src="@/assets/images/login/login_logo.png"alt=""/></div></div><div class="loginBox"><div class="welcomeLogin">欢迎登录</div><el-form ref="formRef" :model="formData" label-width="0px"><el-form-itemprop="account":rules="{ required: true, message: '请输入账号' }"><div class="formLabel">账号</div><el-autocompleteclearableclass="inputStyle"v-model="formData.account":fetch-suggestions="queryAccount"placeholder="请输入账号"@select="chooseAccount"></el-autocomplete></el-form-item><el-form-itemprop="password":rules="{ required: true, message: '请输入密码' }"><div class="formLabel">密码</div><el-inputplaceholder="密码"v-model="formData.password":type="showPassword ? 'text' : 'password'"><i slot="suffix" @click="switchPassword"><imgv-if="showPassword"class="input_icon"src="@/assets/icons/password_show.png"/><imgv-elseclass="input_icon"src="@/assets/icons/password_hide.png"/></i></el-input></el-form-item></el-form><el-checkbox v-model="remember">记住账号</el-checkbox><el-button class="loginBtn" type="primary" @click="login">立即登录</el-button></div></div>
</template><script>
import { api_login } from "@/APIs/login.js";export default {data() {return {accountList: [],remember: false,// 是否显示密码showPassword: false,formData: {},};},mounted() {this.accountList = JSON.parse(localStorage.getItem("accountList")) || [];},methods: {chooseAccount(newAccount) {if (this.accountList.includes(newAccount.value)) {this.remember = true;}this.$nextTick(() => {this.$refs.formRef.clearValidate();});},queryAccount(queryString, cb) {let accountList = JSON.parse(JSON.stringify(this.accountList));accountList = accountList.map((item) => {return {value: item,};});var results = queryString? accountList.filter(this.createFilter(queryString)): accountList;cb(results);},createFilter(queryString) {return (restaurant) => {return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) ===0);};},switchPassword() {this.showPassword = !this.showPassword;},gotoIndex() {this.$router.push("/");},login() {this.$refs.formRef.validate((valid) => {if (valid) {this.loading = this.$loading({text: "登录中",spinner: "el-icon-loading",background: "rgba(0, 0, 0, 0.7)",lock: true,});api_login({...this.formData,}).then((res) => {if (res.data.code === 200) {this.$store.commit("set_token", res.data.data.token);this.$store.commit("set_isLogin", true);delete res.data.data["token"];this.$store.commit("set_userInfo", res.data.data);this.$message({offset: 150,message: "登录成功!",type: "success",});let account = this.formData.account;// 勾选-记住账号if (this.remember) {// 没记住过if (!this.accountList.includes(account)) {// 存入localStoragethis.accountList.push(account);localStorage.setItem("accountList",JSON.stringify(this.accountList));}} else {// 未勾选-记住账号removeItem(this.accountList, account);localStorage.setItem("accountList",JSON.stringify(this.accountList));}this.gotoIndex();} else {this.$message({offset: 150,message: res.data.msg,type: "warning",});}this.loading.close();}).catch(() => {this.loading.close();});}});},},
};// 普通数组移除指定元素
function removeItem(arr, item) {let targetIndex = arr.findIndex((itemTemp) => itemTemp === item);if (targetIndex !== -1) {arr.splice(targetIndex, 1);}
}
</script><style scoped>
.input_icon {cursor: pointer;width: 24px;padding-top: 8px;padding-right: 6px;
}.bg {background-image: url("~@/assets/images/login/login_bg.png");background-size: 100% 100%;position: fixed;top: 0px;width: 100%;height: 100%;
}.loginBox {width: 390px;height: 492px;background: #ffffff;padding: 40px;box-sizing: border-box;
}
.loginPage {display: flex;justify-content: space-around;align-items: center;padding: 0px 90px;box-sizing: border-box;
}
.logoBox {width: 439px;height: 341px;
}
.hello {height: 63px;font-size: 45px;font-family: PingFangSC, PingFang SC;font-weight: 600;color: #ffffff;line-height: 63px;
}
.hello2 {height: 44px;font-size: 32px;font-family: PingFangSC, PingFang SC;font-weight: 600;color: #ffffff;line-height: 44px;margin-bottom: 46px;margin-top: 12px;
}
.welcomeLogin {height: 25px;font-size: 18px;font-family: PingFangSC, PingFang SC;font-weight: 600;color: #2b2d31;line-height: 25px;text-align: center;margin-bottom: 26px;
}
.formLabel {margin-top: 20px;height: 21px;font-size: 15px;font-family: PingFangSC, PingFang SC;font-weight: 400;color: #2b2d31;line-height: 21px;margin-bottom: 10px;
}.loginBtn {height: 51px;background: #3e6ff6;border-radius: 6px;width: 100%;margin-top: 50px;
}
.inputStyle {width: 100%;
}
</style>

配图素材

在这里插入图片描述

在这里插入图片描述

这篇关于vue实战——登录【详解】(含自适配全屏背景,记住账号--支持多账号,显隐密码切换,登录状态保持)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/429058

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c