<template>
  <div class="password-number" :class="{ gutter: gutter != 0 }">
    <div
      class="password-item"
      :class="{ gutter: gutter != 0 }"
      :style="{ margin: `0 ${gutter}px` }"
      v-for="(item, index) in length"
      :key="index"
    >
      <input
        class="password-input"
        @input="_input"
        @keyup="_keyup"
        :type="!password ? 'number' : 'text'"
        :ref="`passwordIndex${index}`"
        :value="!password ? code[index] : passwordViewCode[index]"
        :maxlength="1"
        v-max-length="{ password, mark }"
      />
    </div>
    <div class="mantle" @click="setFocus"></div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      code: "",
      passwordViewCode: "",
    };
  },
  props: {
    //密码数量
    length: {
      type: Number,
      default: 6,
    },
    //是否展示明文
    password: {
      type: Boolean,
      default() {
        return false;
      },
    },
    //加密字符
    mark: {
      type: String,
      default() {
        return "●";
      },
    },
    //格子间距
    gutter: {
      type: String,
      default() {
        return "0";
      },
    },
  },
  directives: {
    /**
     * 自定义指令 最大数量
     */
    maxLength: {
      bind(el, { value }) {
        el.oninput = () => {
          let str = el.value;
          if (el.value.length > 1) {
            if (str.length > 1) {
              el.value = value.password ? value.mark : str.charAt(0);
            } else {
              el.value = str.charAt(0);
            }
          }
        };
      },
    },
  },
  methods: {
    /**
     * 焦点赋值
     */
    setFocus() {
      let _length = this.code.length;
      if (_length < this.length) {
        this.$refs[`passwordIndex${_length}`][0].focus();
      } else {
        this.$refs[`passwordIndex${_length - 1}`][0].focus();
      }
    },
    /**
     * 输入
     */
    _input(e) {
      if (e != null) {
        let str = e.data;
        if (/[^\d]/g.test(str)) {
          str = "";
          this.$refs[`passwordIndex0`][0].value = str;
        }
        if (/^[0-9]+$/.test(str)) {
          if (this.code.length < this.length) {
            this.code += str;
            this.passwordViewCode += this.mark;
            this.setFocus();
          }
          if (this.code.length == this.length) {
            this.$emit("change", this.code);
          }
        }
      }
    },
    /**
     * 删除
     */
    _keyup(e) {
      if (e.keyCode == 8) {
        let str = this.code;
        this.code = str.substr(0, str.length - 1);
        let password_str = this.passwordViewCode;
        this.passwordViewCode = password_str.substr(0, password_str.length - 1);
        this.setFocus();
      }
    },
    /**
     * 重置数据
     */
    resetData() {
      this.code = "";
      this.passwordViewCode = "";
    },
  },
};
</script>
<style lang="scss" scoped>
.password-number {
  height: 40px;
  width: 400px;
  border: 1px solid #ddd;
  display: flex;
  position: relative;
  &.gutter {
    border: 0;
  }
  .mantle {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
  }
  .password-item {
    flex: 1;
    position: relative;
    &::after {
      content: "";
      display: block;
      width: 1px;
      height: 30px;
      background-color: #eee;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      left: 0;
    }
    &:nth-child(1) {
      &::after {
        display: none;
      }
    }
    &.gutter {
      background-color: #eee;
      width: 40px;
      &::after {
        display: none;
      }
    }
    .password-input {
      width: 100%;
      height: 100%;
      text-align: center;
      display: flex;
      align-items: center;
      justify-content: center;
      background: none;
      border: 0;
    }
  }
}
</style>

杭州蘇小小
178 声望12 粉丝

我是一名 WEB前端 开发者不断在前端这条路上努力拼搏着。我喜欢代码的逻辑有序性,每一行代码都有其不同的作用,所有的代码加起来就可以让用户能愉快的体验我的产品。我喜欢研究,遇到难题我不退缩,我相信我可以...