Vue Practical Combat - Login [Detailed Explanation] (Including adaptive full-screen background, remember account - supports multiple accounts, visible and hidden password switching, login status is maintained)

Effect preview

Insert image description here

Technical points - adaptive full-screen background

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

Technical points - password input box

Customize the icon to switch between display and hiding
https://blog.csdn.net/weixin_41192489/article/details/133940676

Technical points - remember account number (supports multiple accounts)

Core requirements and logic

  • Check "Remember Account". Once you log in successfully, you can select the account in the input recommendation list of the account input box next time you log in.

Insert image description here

  • If "Remember Account" is not checked, after successful login, the storage of the account will be cleared.

Related code

When the page loads, get the remembered account

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

Use input boxes with input suggestions

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

Based on the input content, filter out the closest remembered account from the remembered account

    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
        );
      };
    },

In the drop-down selection based on input suggestions, when selecting a remembered account, Remember Account will be automatically checked and the form verification will be cleared.

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

After successfully logging in, you can save a new account or remove the remembered account depending on whether you checked Remember Account.

                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)
                  );
                }

Tool functions used

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

Technical Points - Stay logged in after logging in

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

Complete sample code

<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>

Picture material

Insert image description here

Insert image description here

Guess you like

Origin blog.csdn.net/weixin_41192489/article/details/134651294