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

news2024/11/27 14:31:28

效果预览

在这里插入图片描述

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

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-autocomplete
            clearable
            class="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)) {
                    // 存入localStorage
                    this.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">
        <img
          class="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-item
          prop="account"
          :rules="{ required: true, message: '请输入账号' }"
        >
          <div class="formLabel">账号</div>
          <el-autocomplete
            clearable
            class="inputStyle"
            v-model="formData.account"
            :fetch-suggestions="queryAccount"
            placeholder="请输入账号"
            @select="chooseAccount"
          ></el-autocomplete>
        </el-form-item>
        <el-form-item
          prop="password"
          :rules="{ required: true, message: '请输入密码' }"
        >
          <div class="formLabel">密码</div>
          <el-input
            placeholder="密码"
            v-model="formData.password"
            :type="showPassword ? 'text' : 'password'"
          >
            <i slot="suffix" @click="switchPassword">
              <img
                v-if="showPassword"
                class="input_icon"
                src="@/assets/icons/password_show.png"
              />
              <img
                v-else
                class="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)) {
                    // 存入localStorage
                    this.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>

配图素材

在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「江鸟中原」有关HarmonyOS-ArkTS的Http通信请求

一、Http简介 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于在Web应用程序之间进行通信的协议&#xff0c;通过运输层的TCP协议建立连接、传输数据。Http通信数据以报文的形式进行传输。Http的一次事务包括一个请求和一个响应。 Http通信是基于客户端-服…

进程等待讲解

今日为大家分享有关进程等待的知识&#xff01;希望读完本文&#xff0c;大家能有一定的收获&#xff01; 正文开始&#xff01; 进程等待的引进 既然我们今天要讲进程等待这个概念&#xff01;那么只有我们把下面这三个方面搞明白&#xff0c;才能真正的了解进程等待&#x…

形象建设、生意经营、用户运营,汽车品牌如何在小红书一举多得?

随着小红书在多领域的持续成长&#xff0c;现在来小红书看汽车的用户&#xff0c;需求逐渐多元化与专业化。近1年的时间&#xff0c;有超过1亿人在小红书「主动搜索」过汽车内容&#xff0c;大家已经不仅限于玩车、用车&#xff0c;更是扩展到了百科全书式的看、选、买、学各个…

Python3 selenium 设置元素等待的三种方法

为什么要设置元素等待&#xff1f; 当你的网络慢的时候&#xff0c;打开网页慢&#xff0c;网页都没完全打开&#xff0c;代码已经在执行了&#xff0c;但是没找到你定位的元素&#xff0c;此时python会报错。 当你的浏览器或电脑反应慢&#xff0c;网页没完全打开&#xff0c;…

12、模块化编程

模块化编程 1、传统方式编程&#xff1a;所有的函数均放在main.c里&#xff0c;若使用的模块比较多&#xff0c;则一个文件内会有很多的代码&#xff0c;不利于代码的组织和管理&#xff0c;而且很影响便朝着的思路 2、模块化编程&#xff1a;把各个模块的代码放在不同的.c文件…

java--单继承、Object

java是单继承的&#xff0c;java中的类不支持多继承&#xff0c;但是支持多层继承。 反证法&#xff1a; 如果一个类同时继承两个类&#xff0c;然后两个类中都有同样的一个方法&#xff0c;哪当我创建这个类里的方法&#xff0c;是调用哪父类的方法 所以java中的类不支持多继…

PostgreSQL + SQL Server = WiltonDB

WiltonDB 是一个基于 PostgreSQL 的开源数据库&#xff0c;通过 Babelfish 插件支持 Microsoft SQL Server 协议以及 T-SQL 语句。 Babelfish 是亚马逊提供的一个开源项目&#xff0c;使得 PostgreSQL 数据库同时具有 Microsoft SQL Server 数据查询和处理的能力。Babelfish 可…

11、动态数码管显示

数码管驱动方式 1、单片机直接扫描&#xff1a;硬件设备简单&#xff0c;但会消耗大量的单片机CPU时间 2、专用驱动芯片&#xff1a;内部自带显存、扫描电路&#xff0c;单片机只需告诉他显示什么即可 #include <REGX52.H> //数组代表显示亮灯的内容0、1、2、3、4、5、…

单车模型及其线性化

文章目录 1 单车模型2 线性化3 实现效果4 参考资料 1 单车模型 这里讨论的是以后轴为中心的单车运动学模型&#xff0c;由下式表达&#xff1a; S ˙ [ x ˙ y ˙ ψ ˙ ] [ v c o s ( ψ ) v s i n ( ψ ) v t a n ( ψ ) L ] \dot S \begin{bmatrix} \dot x\\ \dot y\\ \d…

C++ : 初始化列表 类对象作为类成员

传统方式初始化 C 提供了初始化列表语法&#xff0c;用来初始化属性 初始化列表 语法&#xff1a; 构造函数()&#xff1a;属性1(值1), 属性2&#xff08;值2&#xff09;... {} class Person { public://传统方式初始化 Person(int a, int b, int c) {m_A a;m_B b;m_C c…

python之pyqt专栏6-信号与槽2

上一篇python之pyqt专栏5-信号与槽1-CSDN博客&#xff0c;我们通过信号与槽实现了点击Button&#xff0c;改变Label的文本内容。可以知道 信号是在类中定义的&#xff0c;是类的属性 槽函数是信号通过connect连接的任意成员函数&#xff0c;当信号发生时&#xff0c;执行与信号…

FFmpeg架构全面分析

一、简介 它的官网为&#xff1a;https://ffmpeg.org/&#xff0c;由Fabrice Bellard&#xff08;法国著名程序员Born in 1972&#xff09;于2000年发起创建的开源项目。该人是个牛人&#xff0c;在很多领域都有很大的贡献。 FFmpeg是多媒体领域的万能工具。只要涉及音视频领…

Selenium-Unittest单元测试框架

1、Unittest介绍 为什么要学习单元测试框架 测试用例的组织与运行需要单元测试框架的参与&#xff0c;从而满足不同测试场景的需要&#xff0c;单元测试框架提供了丰富的比较方法&#xff1a;实际结果与预期结果的对比测试结果 单元测试框架提供了丰富的日志&#xff1a;给出测…

【SQL Server Management】使用手册

目录 ⛳️【SQL Server Management】 ⛳️1. 启动登录 ⛳️2. 忘记密码 ⛳️3. 操作数据库和表 3.1 新建数据库text 3.2 新建表 3.3 编辑表 3.4 编写脚本 ⛳️【SQL Server Management】 ⛳️1. 启动登录 需要开启服务 ⛳️2. 忘记密码 登录windows--> 安全性 -->…

mycat快速搭建

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;博主会及时修改 mycat快速搭建 在主从数据库集群架构中&#xff0c;让主库负责处理写入操作&#xff0c;而从库只负责处理select查询&am…

振南技术干货集:FFT 你知道?那数字相敏检波 DPSD 呢?(1)

注解目录 1 、DPSD 的基础知识 1.1 应用模型 1.2 原理推导 1.3 硬件 PSD &#xff08;相敏检波&#xff0c;就是从繁乱复杂的信号中将我们关心的信号检出来&#xff0c;同时对相位敏感。 数学原理&#xff0c;逃不掉的&#xff0c;硬着头皮看吧。&#xff09; 2 、DPSD …

坚鹏:基于招商银行案例研究的银行APP运营成功之道培训圆满结束

中国邮政储蓄银行拥有优良的资产质量和显著的成长潜力&#xff0c;是中国领先的大型零售银行。2016年9月在香港联交所挂牌上市&#xff0c;2019年12月在上交所挂牌上市。中国邮政储蓄银行拥有近4万个营业网点&#xff0c;服务个人客户超6.5亿户。2022年&#xff0c;在《银行家》…

Linux(10):Shell scripts

什么是 Shell scripts shell script&#xff08;程序化脚本&#xff09;&#xff1a;shell 部分是一个文字接口下让我们与系统沟通的一个工具接口&#xff1b;script 是脚本的意思&#xff0c;shell script 就是针对 shell 写的脚本。 shell script 是利用 shell 的功能所写的…

【ONE·Linux || 网络基础(四)】

总言 主要内容&#xff1a;传输层UDP、TCP协议基本介绍。UDP报文格式、TCP报文格式、三次握手四次挥手、TCP可靠性策略说明。 文章目录 总言8、UDP协议&#xff08;传输层一&#xff09;8.1、传输层预备知识8.1.1、端口号8.1.2、一些指令&#xff08;netstat、pidof、xargs&am…

UE4/UE5 雾

雾 UE4/UE5 雾平面雾材质效果图&#xff1a; 3D雾区材质效果图&#xff1a; UE4/UE5 雾 平面雾 做好将材质放在Plane上就行 材质 效果图&#xff1a; 3D雾区 做好将材质放在3D模型上就行 材质 效果图&#xff1a;