Vue2 中封装密码输入框组件

996 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

Vue2 中封装密码输入框组件

该组件主要实现了以下三块内容:

  • 密码值的显示与隐藏
  • 密码强度的检测
  • 提示文字的显示与隐藏

最终的实现效果: 效果图.gif

1.密码组件的基本介绍

1.1 参数与事件

参数见下表:

参数说明类型是否必填默认值
value密码值String——
PWStrengthTest是否开启密码检测Booleanfalse
PWLevel密码强度Number0

事件见下表:

事件说明形参
changeValue密码值变化时触发新的密码值
changePWLevel密码强度变化时触发新的密码强度

1.2 使用该组件的示例

<template>
  <form class="form">
    <PasswordComp
      :value="passwordVal"
      @changeValue="passwordVal = $event"
      :PWStrengthTest="true"
      :PWLevel="PWLevel"
      @changePWLevel="PWLevel = $event"
    ></PasswordComp>
  </form>
</template>
<script>
import PasswordComp from "@/components/PasswordComp.vue";
export default {
  components: {
    PasswordComp,
  },
  data() {
    return {
      passwordVal: "",
      PWLevel: 0,
    };
  },
};
</script>

2. 功能的实现原理

2.1 密码的显示与隐藏

控制密码的显示与隐藏的主要思路:

  • 点击小眼睛图标触发input 元素的 type 属性值的更改
    • 密码显示时type=text
    • 密码隐藏时type=password

在 vue 中使用 computed 计算属性来监听 data 中的 isShow 值,得出 input 元素的 type 属性值以及 img 元素的 src 属性值。 该部分的主要代码如下:

<template>
  <div class="password-container">
    <div class="password">
      <input
        ref="password"
        name="password"
        maxlength="16"
        :type="inputType"
      />
      <img :src="imgSrc" alt="eye" @click="changeType" />
    </div>
  </div>
</template>
<script>
export default {
   props: {
    value: {
      type: String,
      required: true,
    }
  },
  data() {
    return {
      isShow: false, //密码的显示与隐藏 true表示显示 false表示隐藏
    };
  },
  computed: {
    inputType() {
      return this.isShow ? "text" : "password";
    },
    imgSrc() {
      return this.isShow
        ? "https://s4.ax1x.com/2022/01/07/79E7dg.png"
        : "https://s4.ax1x.com/2022/01/07/79EOWn.png";
    },
  },
  methods: {
    //改变显示模式
    changeType() {
      this.isShow = !this.isShow;
    },
  },

};
</script>

2.2 密码强度的检测

检测密码强度主要思路是:

  • 每当父组件通过 props 属性传入 value 值时,子组件先通过 watch 监听该值并使用正则表达式来计算强度,再通过 computed 计算属性与 class 类名来进行相应的样式控制。

该部分的主要代码如下:

<template>
  <div class="password-container">
    <div class="password">
      <input
        ref="password"
        name="password"
        maxlength="16"
        :value="value"
        @input="changeValue"
      />
    </div>
    <div class="PWStrengthTest" v-if="PWStrengthTest">
      <span>密码强度</span>
      <span v-if="PWLevel">:</span>
      <span
        class="PWString"
        :class="{
          easy: PWLevel === 1,
          medium: PWLevel === 2,
          difficulty: PWLevel === 3 || PWLevel === 4,
        }"
        >{{ PWLevelText }}
      </span>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: String,
      required: true,
    },
    PWStrengthTest: {
      type: Boolean,
      default: false, //true表示开启密码检测 false表示关闭
    },
    PWLevel: {
      type: Number,
      default: 0, //0表示未输入 1表示弱 2表示中单 3表示强 4表示很强
    },
  },
  computed: {
    PWLevelText() {
      if (this.PWLevel === 0) {
        return "";
      } else if (this.PWLevel === 1) {
        return "弱";
      } else if (this.PWLevel === 2) {
        return "中等";
      } else if (this.PWLevel === 3) {
        return "强";
      } else if (this.PWLevel === 4) {
        return "很强";
      }
    },
  },
  methods: {
    //改变密码的值
    changeValue() {
      this.$emit("changeValue", this.$refs.password.value);
    },
  },
  watch: {
    //检测密码强度
    value: function (newVal) {
      if (!this.PWStrengthTest) return;
      let curPWLevel = 0;
      if (newVal.length >= 6) {
        //密码长度大于6时开始监测密码等级
        if (/\d/.test(newVal)) curPWLevel++; //数字
        if (/[a-z]/.test(newVal)) curPWLevel++; //小写字母
        if (/[A-Z]/.test(newVal)) curPWLevel++; //大写字母
        if (/\W/.test(newVal)) curPWLevel++; //特殊字符
      }
      if (curPWLevel !== this.PWLevel) {
        this.$emit("changePWLevel", curPWLevel);
      }
    },
  },
};
</script>

2.3 提示文字的显示与隐藏

控制提示文字的显示与隐藏的主要思路是:

  • 通过 data 属性中的 msgShow 来控制该元素的 visibility 属性值
    • 密码框触发 focus 事件时,将msgShow = true
    • 密码框触发 blur 事件时,将msgShow = false

该部分的主要代码如下:

<template>
  <div class="password-container">
    <p class="msg" :class="{ active: msgShow }">
      请输入6-16位的密码(至少包含两种字符类型)
    </p>
    <div class="password">
      <input
        ref="password"
        name="password"
        maxlength="16"
        @focus="msgShow = true"
        @blur="msgShow = false"
      />
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      msgShow: false, //提示文字的显示与隐藏
    };
  },
};
</script>

3. 组件的完整代码

<template>
  <div class="password-container">
    <p class="msg" :class="{ active: msgShow }">
      请输入6-16位的密码(至少包含两种字符类型)
    </p>
    <div class="password">
      <input
        ref="password"
        name="password"
        maxlength="16"
        :type="inputType"
        :value="value"
        @input="changeValue"
        @focus="msgShow = true"
        @blur="msgShow = false"
      />
      <img :src="imgSrc" alt="eye" @click="changeType" />
    </div>
    <div class="PWStrengthTest" v-if="PWStrengthTest">
      <span>密码强度</span>
      <span v-if="PWLevel">:</span>
      <span
        class="PWString"
        :class="{
          easy: PWLevel === 1,
          medium: PWLevel === 2,
          difficulty: PWLevel === 3 || PWLevel === 4,
        }"
        >{{ PWLevelText }}
      </span>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: String,
      required: true,
    },
    PWStrengthTest: {
      type: Boolean,
      default: false, //true表示开启密码检测 false表示关闭
    },
    PWLevel: {
      type: Number,
      default: 0, //0表示未输入 1表示弱 2表示中单 3表示强 4表示很强
    },
  },
  data() {
    return {
      isShow: false, //密码的显示与隐藏 true表示显示 false表示隐藏
      msgShow: false, //提示文字的显示与隐藏
    };
  },
  computed: {
    inputType() {
      return this.isShow ? "text" : "password";
    },
    imgSrc() {
      return this.isShow
        ? "https://s4.ax1x.com/2022/01/07/79E7dg.png"
        : "https://s4.ax1x.com/2022/01/07/79EOWn.png";
    },
    PWLevelText() {
      if (this.PWLevel === 0) {
        return "";
      } else if (this.PWLevel === 1) {
        return "弱";
      } else if (this.PWLevel === 2) {
        return "中等";
      } else if (this.PWLevel === 3) {
        return "强";
      } else if (this.PWLevel === 4) {
        return "很强";
      }
    },
  },
  methods: {
    //改变显示模式
    changeType() {
      this.isShow = !this.isShow;
    },
    //改变密码的值
    changeValue() {
      this.$emit("changeValue", this.$refs.password.value);
    },
  },
  watch: {
    //检测密码强度
    value: function (newVal) {
      if (!this.PWStrengthTest) return;
      let curPWLevel = 0;
      if (newVal.length >= 6) {
        //密码长度大于6时开始监测密码等级
        if (/\d/.test(newVal)) curPWLevel++; //数字
        if (/[a-z]/.test(newVal)) curPWLevel++; //小写字母
        if (/[A-Z]/.test(newVal)) curPWLevel++; //大写字母
        if (/\W/.test(newVal)) curPWLevel++; //特殊字符
      }
      if (curPWLevel !== this.PWLevel) {
        this.$emit("changePWLevel", curPWLevel);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.password-container {
  width: 300px;
  display: flex;
  flex-direction: column;
  .msg {
    align-self: flex-end;
    font-size: 14px;
    margin: 0;
    color: #ccc;
    visibility: hidden;
    &.active {
      visibility: visible;
    }
  }
  .password {
    position: relative;
    input {
      margin-top: auto;
      width: 100%;
      height: 28px;
      box-sizing: border-box;
      outline: none;
      border: 1px solid #4d4ddb;
      border-radius: 2px;
      padding: 0 6px;
      &:focus {
        border: 1px solid #000;
      }
    }
    img {
      position: absolute;
      width: 14px;
      height: 14px;
      top: 50%;
      right: 5px;
      transform: translateY(-50%);
      cursor: pointer;
    }
  }
  .PWStrengthTest {
    width: 100%;
    margin-top: 4px;
    font-size: 14px;
    display: flex;
    span {
      font-size: 14px;
    }
    .PWString {
      &.easy {
        color: rgb(251, 7, 7);
      }
      &.medium {
        color: rgb(255, 185, 0);
      }
      &.difficulty {
        color: rgb(0, 255, 133);
      }
    }
  }
}
</style>

结语

这是我目前所了解的知识面中最好的解答,当然也有可能存在一定的误区。

所以如果对本文存在疑惑,可以在评论区留言,我会及时回复的,欢迎大家指出文中的错误观点。

最后码字不易,觉得有帮助的朋友点赞、收藏、关注走一波。