浏览器自动填充登录用户名和密码,如何清除

文章目录

刷新网页的时候浏览器会自动填充用户名和密码

刷新之后效果图

解决方案

完整的login.vue代码

javascript 复制代码
<template>
  <div class="login">
    <el-card>
      <h2 class="title"  style="text-align: center; font-weight: bold; color: #707070;">数字化监管平台</h2>
      <el-tabs v-model="activeName" @tab-click="handleClick" stretch>
        <el-tab-pane label="机构和姓名登录" name="first">
          <div class="form-container">
            <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">

            <el-form-item label="" prop="deptId">
              <treeselect class="el-treeselect" v-model="loginForm.deptId" :options="deptOptions" :show-count="true"
                          placeholder="请选择归属机构"/>
              <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
            </el-form-item>

            <el-form-item prop="nickName">
              <el-input
                v-model="loginForm.nickName"
                type="text"
                auto-complete="off"
                placeholder="姓名"
                :readonly="isReadOnly"
                @focus="handleFocus"
              >
                <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
              </el-input>
            </el-form-item>
            <el-form-item prop="password">
              <el-input
                v-model="loginForm.password"
                type="password"
                auto-complete="off"
                placeholder="密码"
                @keyup.enter.native="handleLogin"
                :readonly="isReadOnly"
                @focus="handleFocus"
              >
                <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
              </el-input>
            </el-form-item>
            <el-form-item prop="code" v-if="captchaEnabled">
              <el-input
                v-model="loginForm.code"
                auto-complete="off"
                placeholder="验证码"
                style="width: 63%"
                @keyup.enter.native="handleLogin"
              >
                <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon"/>
              </el-input>
              <div class="login-code">
                <img :src="codeUrl" @click="getCode" class="login-code-img"/>
              </div>
            </el-form-item>
            <el-form-item style="width:100%;">
              <el-button
                :loading="loading"
                size="medium"
                type="primary"
                style="width:100%;"
                @click.native.prevent="handleLoginByOrg"
              >
                <span v-if="!loading">登 录</span>
                <span v-else>登 录 中...</span>
              </el-button>
            </el-form-item>
          </el-form>
          </div>
        </el-tab-pane>

        <el-tab-pane label="用户名登录" name="second">
          <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
            <el-form-item prop="username">
              <el-input
                v-model="loginForm.username"
                type="text"
                auto-complete="off"
                placeholder="账号"
                :readonly="isReadOnly"
                @focus="handleFocus"
              >
                <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
              </el-input>
            </el-form-item>
            <el-form-item prop="password">
              <el-input
                v-model="loginForm.password"
                type="password"
                auto-complete="off"
                placeholder="密码"
                @keyup.enter.native="handleLogin"
                :readonly="isReadOnly"
                @focus="handleFocus"
              >
                <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
              </el-input>
            </el-form-item>
            <el-form-item prop="code" v-if="captchaEnabled">
              <el-input
                v-model="loginForm.code"
                auto-complete="off"
                placeholder="验证码"
                style="width: 63%"
                @keyup.enter.native="handleLogin"
              >
                <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon"/>
              </el-input>
              <div class="login-code">
                <img :src="codeUrl" @click="getCode" class="login-code-img"/>
              </div>
            </el-form-item>
            <el-form-item style="width:100%;">
              <el-button
                :loading="loading"
                size="medium"
                type="primary"
                style="width:100%;"
                @click.native.prevent="handleLogin"
              >
                <span v-if="!loading">登 录</span>
                <span v-else>登 录 中...</span>
              </el-button>
              <div style="float: right;" v-if="register">
                <router-link class="link-type" :to="'/register'">立即注册</router-link>
              </div>
            </el-form-item>
          </el-form>
          <!--  底部  -->
          <!-- <div class="el-login-footer">
            <span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
          </div> -->
        </el-tab-pane>
      </el-tabs>
    </el-card>

  </div>

</template>

<script>
  import {getCodeImg} from "@/api/login";
  import Cookies from "js-cookie";
  import {encrypt, decrypt} from '@/utils/jsencrypt';
  import {deptTreeSelect} from "@/api/system/user";
  import Treeselect from "@riophae/vue-treeselect";
  import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  import {Message} from 'element-ui'

  export default {
    name: "Login",
    components: {Treeselect},
    data() {
      return {
        codeUrl: "",
        loginForm: {
          username: "",
          password: "",
          rememberMe: false,
          code: "",
          uuid: ""
        },
        loginRules: {
          username: [
            {required: true, trigger: "blur", message: "请输入您的账号"}
          ],
          password: [
            {required: true, trigger: "blur", message: "请输入您的密码"}
          ],
          code: [{required: true, trigger: "change", message: "请输入验证码"}]
        },
        loading: false,
        // 验证码开关
        captchaEnabled: true,
        // 注册开关
        register: false,
        redirect: undefined,
        activeName: 'first',
        // 部门树选项
        deptOptions: undefined,
        isReadOnly: true
      };
    },
    watch: {
      $route: {
        handler: function (route) {
          this.redirect = route.query && route.query.redirect;
        },
        immediate: true
      }
    },
    created() {
      this.getDeptTree();
      this.getCode();
    },
    methods: {
      getCode() {
        getCodeImg().then(res => {
          this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
          if (this.captchaEnabled) {
            this.codeUrl = "data:image/gif;base64," + res.img;
            this.loginForm.uuid = res.uuid;
          }
        });
      },
      handleLogin() {
        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true;
            if (this.loginForm.rememberMe) {
              Cookies.set("username", this.loginForm.username, {expires: 30});
              Cookies.set("password", encrypt(this.loginForm.password), {expires: 30});
              Cookies.set('rememberMe', this.loginForm.rememberMe, {expires: 30});
            } else {
              Cookies.remove("username");
              Cookies.remove("password");
              Cookies.remove('rememberMe');
            }
            this.$store.dispatch("Login", this.loginForm).then(() => {
              this.$router.push({path: this.redirect || "/"}).catch(() => {
              });
            }).catch(() => {
              this.loading = false;
              if (this.captchaEnabled) {
                this.getCode();
              }
            });
          }
        });
      },
      handleLoginByOrg() {
        //校验
        if (!this.loginForm.nickName) {
          Message.info("用户名称不能为空!");
          return;
        }
        if (!this.loginForm.deptId || this.loginForm.deptId === undefined) {
          Message.info("请选择机构名称!");
          return;
        }
        if (!this.loginForm.password) {
          Message.info("密码不能为空!");
          return;
        }

        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true;
            if (this.loginForm.rememberMe) {
              Cookies.set("deptId", this.loginForm.deptId, {expires: 30});
              Cookies.set("nickName", this.loginForm.nickName, {expires: 30});
              Cookies.set("username", this.loginForm.username, {expires: 30});
              Cookies.set("password", encrypt(this.loginForm.password), {expires: 30});
              Cookies.set('rememberMe', this.loginForm.rememberMe, {expires: 30});
            } else {
              Cookies.remove("nickName");
              Cookies.remove("username");
              Cookies.remove("password");
              Cookies.remove('rememberMe');
            }
            this.$store.dispatch("LoginByOrg", this.loginForm).then(response => {
              console.log('response', response);
              Message.info(response)
              this.$router.push({path: this.redirect || "/"}).catch(() => {
              });
              this.loading = false;
            }).catch(() => {
              this.loading = false;
              if (this.captchaEnabled) {
                this.getCode();
              }
            });
          }
        });
      },
      handleClick(tab, event) {
        console.log(tab, event);
      },
      /** 查询部门下拉树结构 */
      getDeptTree() {
        deptTreeSelect().then(response => {
          this.deptOptions = response.data;
        });
      },
      handleFocus(event) {
        this.isReadOnly = false;
        // 可能还需要在某些情况下重新聚焦,以确保输入框获得焦点
        // event.target.blur();
        // event.target.focus();
      },
    }
  };
</script>

<style rel="stylesheet/scss" lang="scss">
  .login {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100%;
    background-image: url("../assets/images/login-new.png");
    background-size: cover;
  }

  .el-tabs {
    background-color: #ffffff; /* 设置底色为白色 */
  }

  .login-form {
    border-radius: 6px;
    background: #ffffff;
    width: 400px;
    padding: 25px 25px 5px 25px;

    .el-input {
      height: 38px;

      input {
        height: 38px;
      }
    }

    .input-icon {
      height: 39px;
      width: 14px;
      margin-left: 2px;
    }
  }

  .login-tip {
    font-size: 13px;
    text-align: center;
    color: #bfbfbf;
  }

  .login-code {
    width: 33%;
    height: 38px;
    float: right;

    img {
      cursor: pointer;
      vertical-align: middle;
    }
  }

  .login-code-img {
    height: 38px;
  }

  .form-container {
    overflow-y: auto;
  }


</style>

核心代码原理(添加 readonly 和监听 focus 事件)

用户名和密码字段即使没有赋值也出现浏览器自动填充的情况,可以采用以下方法来禁止这一行为:

  1. 使用 auto-complete 属性 (实测并没有生效):

    对于 el-input 组件,你应该将 auto-complete 属性设置为 "new-password",即使对于非密码字段也是如此,因为某些浏览器可能对常见的字段名有所识别并尝试自动填充。例如:

    html 复制代码
    <el-input v-model="username" auto-complete="new-password"></el-input>
    <el-input v-model="password" type="password" auto-complete="new-password"></el-input>
  2. 添加 readonly 和监听 focus 事件 (实测有效):

    初始时设置输入框为只读(readonly),并在获得焦点时移除只读属性,这可以阻止某些浏览器的自动填充功能。需要在组件的 focus 事件中移除 readonly

    html 复制代码
    <el-input
      v-model="username"
      auto-complete="new-password"
      :readonly="isReadOnly"
      @focus="handleFocus"
    ></el-input>
    
    <script>
    export default {
      data() {
        return {
          username: '',
          isReadOnly: true,
        };
      },
      methods: {
        handleFocus(event) {
          this.isReadOnly = false;
          // 可能还需要在某些情况下重新聚焦,以确保输入框获得焦点
          // event.target.blur();
          // event.target.focus();
        },
      },
    };
    </script>
相关推荐
web前端神器23 分钟前
forever启动后端服务,自带日志如何查看与设置
前端·javascript·vue.js
才艺のblog25 分钟前
127还是localhost....?
javascript·https·浏览器特性
是Yu欸28 分钟前
【前端实现】在父组件中调用公共子组件:注意事项&逻辑示例 + 将后端数组数据格式转换为前端对象数组形式 + 增加和删除行
前端·vue.js·笔记·ui·vue
今天是 几 号38 分钟前
WEB攻防-XSS跨站&反射型&存储型&DOM型&标签闭合&输入输出&JS代码解析
前端·javascript·xss
进击的阿三姐1 小时前
vue2项目迁移vue3与gogocode的使用
前端·javascript·vue.js
java一只鱼1 小时前
基于Spring Boot的先进时尚室内管理系统
spring boot·mysql·elementui·vue·layui
风火一回2 小时前
webpack+webpack server入门
javascript·webpack
CiL#2 小时前
vue2+element-ui新增编辑表格+删除行
前端·vue.js·elementui
nbsaas-boot3 小时前
为什么面向对象的设计方法逐渐减少
前端·javascript·vue.js
binnnngo3 小时前
网页计算器的实现
javascript·css3·html5