使用css解决input type=“password”在浏览器中出现历史密码记录弹窗问题

669 阅读1分钟

需求背景:甲方要求在密码输入框一栏,focus在input框时,不能弹出该网站的历史密码,eg: 如下图

image.png

注:本例以element-ui v2.15.4的el-input举例

  1. 【2021-01-14】 首次编辑
  2. 【2021-01-15】针对不可行的方案三,发现有解决方案,可参考掘金网友的解决方案,详见:juejin.cn/post/691639…

最终敲定的解决方案:使用 @font-face 参考文章:stackoverflow.com/questions/3…

实现代码依赖包:www.npmjs.com/package/tex…

因为项目中只用到了disc,故在下载的包中抽离出了disc的相关文件内容

<el-input
  v-model.trim="userForm.password"
  type="text"
  placeholder="包含字母和数字(7-14位)"
  maxlength="14"
  autocomplete="off"
  :class="isShowPwd ? '' : 'text-security-as-password'"
>
  <i
    slot="suffix"
    class="el-input__icon el-icon-view cursor-pointer"
    @click="isShowPwd = !isShowPwd"
  />
</el-input>

<script>
    data() {
        return {
            isShowPwd: false
        }
    }
</script>

<style>
    @font-face {
      font-family: 'text-security-disc';
      src: url('text-security-disc-compat.eot');
      src: url('text-security-disc-compat.eot?#iefix') format('embedded-opentype'),
        url('text-security-disc-compat.woff2') format('woff2'),
        url('text-security-disc-compat.ttf') format('truetype');
    }
    @supports ((content-visibility: visible) or (-moz-appearance: meter)) and
      (not (-webkit-hyphens: none)) {
      @font-face {
        font-family: 'text-security-disc';
        src: url('text-security-disc.woff2') format('woff2'),
          url('text-security-disc-compat.ttf') format('truetype');
      }
    }
    .text-security-as-password {
      font-family: text-security-disc;
    }
    .el-input input::placeholder {
      font-family: initial;
    }
    .el-input input::-webkit-input-placeholder {
      font-family: initial;
    }
    .el-input input::-moz-placeholder {
      font-family: initial;
    }
    .el-input input::-ms-placeholder {
      font-family: initial;
    }
    .el-input input:-ms-input-placeholder {
      font-family: initial;
    }
</style>

以下是尝试的各种不可行方案

尝试一:(不可行)

  1. 设置一个紧挨着的密码框的input,‘欺骗’浏览器
<!-- 隐藏的框,欺骗浏览器进行填充 -->
<el-input type="password" v-model="userForm.password" style="display: none" />
<!-- 真正的密码输入框 -->
<el-input type="password" v-model="userForm.password" show-password autocomplete="off" />

尝试二:(存在浏览器兼容性问题,可通过caniuse.com/?search=tex… 查看兼容情况)

<!-- type为text,设置input的样式 -->
<el-input type="text" v-model="userForm.password" autocomplete="off" class="fake-password" />

<style>
    .fake-password {
      -webkit-text-security: disc;
    }
</style>

尝试三:(不可行)

<el-input
  v-model="userForm.password"
  autocomplete="off"
  :type="pwdType"
  @focus="onFocus"
  @input="onInput"
/>

data() {
    return {
        pwdType: 'text'
    }
},
methods: {
    onFocus() {
      this.pwdType = 'password'
    },
    onInput(val) {
      this.pwdType = val ? 'password' : 'text'
    },
}

问题1:首次聚焦没问题,失焦后二次聚焦仍会出现密码框

image.png

image.png

问题2:回退清空时仍会弹出密码框

image.png

问题3: 因为focus时会设置成password,则如果要实现密码切换功能时,也会存在问题

尝试四:(不可行)

1.使用正则替换input的文本为 ·,在中文输入法输入中文的情况下会有问题,切输入中文时,需要在下一步输入时,上一步的中文才会变成**·**

<el-input
  v-model="userForm.password"
  type="text"
  autocomplete="off"
  @input.native="onInput($event)"
/>

methods: {
    // 以下代码还存在问题,不可取
    onInput(e) {
      const reg = /./g
      const { newpassword1 } = this.createForm
      if (newpassword1) this.createForm.newpassword1 = newpassword1.replace(reg, '•')
      const start = e.srcElement.selectionStart
      if (e.data) {
        this.realPwd.splice(start, 0, e.data)
      } else {
        this.realPwd.splice(start, 1)
      }
      if (start === 0 && !newpassword1 && !e.data) {
        this.realPwd = []
      }
    }
}