[聚合文章] 使用VUE分分钟写一个验证码输入组件

JavaScript 2017-12-14 25 阅读

先来看波完成效果图

需求

输入4位或6位短信验证码,输入完成后收起键盘

实现步骤

第一步

布局排版

<div class="security-code-wrap">
    <label for="code">
      <ul class="security-code-container">
        <li class="field-wrap" v-for="(item, index) in number" :key="index">
          <i class="char-field">{{value[index] || placeholder}}</i>
        </li>
      </ul>
    </label>
    <input ref="input" class="input-code" @keyup="handleInput($event)" v-model="value"
           id="code" name="code" type="tel" :maxlength="number"
           autocorrect="off" autocomplete="off" autocapitalize="off">
</div>
  • 使用li元素来模拟输入框的显示,没有别的目的,就只是为了语义化,当然你也可以使用其他任意一个元素来模拟,比如div。
  • 使用label标签的好处在于它可以跟input的click事件关联上,一方面实现了语义化解决方案,另一方面也省去了我们通过js来唤起虚拟键盘。

隐藏输入框

.input-code {
    position: absolute;
    left: -9999px;
    top: -99999px;
    width: 0;
    height: 0;
    opacity: 0;
    overflow: visible;
    z-index: -1;
}
  • 将真实的输入框定位到屏幕可视区域以外的地方,虚拟键盘被唤起时,就不会将页面往上顶了。所以你的验证码输入组件一定要放在虚拟键盘遮挡不了的地方。

第二步

处理验证码输入

handleSubmit() {
    this.$emit('input', this.value)
},
handleInput(e) {
    this.$refs.input.value = this.value
    if (this.value.length >= this.number) {
        this.hideKeyboard()
    }
    this.handleSubmit()
}
  • 输入时,给输入框赋一次值,是为了解决android端上输入框失焦后重新聚焦,输入光标会定在第一位的前面,经过赋值再聚焦,光标的位置就会显示在最后一位后面。

第三步

完成输入后关闭虚拟键盘

hideKeyboard() {
    // 输入完成隐藏键盘
    document.activeElement.blur() // ios隐藏键盘
    this.$refs.input.blur() // android隐藏键盘
}

组件完整代码

<!--四位验证码输入框组件-->
<template>
  <div class="security-code-wrap">
    <label for="code">
      <ul class="security-code-container">
        <li class="field-wrap" v-for="(item, index) in number" :key="index">
          <i class="char-field">{{value[index] || placeholder}}</i>
        </li>
      </ul>
    </label>
    <input ref="input" class="input-code" @keyup="handleInput($event)" v-model="value"
           id="code" name="code" type="tel" :maxlength="number"
           autocorrect="off" autocomplete="off" autocapitalize="off">
  </div>
</template>

<script>
  export default {
    name: 'SecurityCode',
    // component properties
    props: {
      number: {
        type: Number,
        default: 4
      },
      placeholder: {
        type: String,
        default: '-'
      }
    },
    // variables
    data() {
      return {
        value: ''
      }
    },
    methods: {
      hideKeyboard() {
        // 输入完成隐藏键盘
        document.activeElement.blur() // ios隐藏键盘
        this.$refs.input.blur() // android隐藏键盘
      },
      handleSubmit() {
        this.$emit('input', this.value)
      },
      handleInput(e) {
        this.$refs.input.value = this.value
        if (this.value.length >= this.number) {
          this.hideKeyboard()
        }
        this.handleSubmit()
      }
    }
  }
</script>

<style scoped lang="less">
  .security-code-wrap {
    overflow: hidden;
  }

  .security-code-container {
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    .field-wrap {
      list-style: none;
      display: block;
      width: 40px;
      height: 40px;
      line-height: 40px;
      font-size: 16px;
      background-color: #fff;
      margin: 2px;
      color: #000;
      .char-field {
        font-style: normal;
      }
    }
  }

  .input-code {
    position: absolute;
    left: -9999px;
    top: -99999px;
    width: 0;
    height: 0;
    opacity: 0;
    overflow: visible;
    z-index: -1;
  }

</style>

组件使用代码

<security-code v-model="authCode"></security-code>

结束语

怎么样,484 so easy

一开始的思路也是4个输入框,监听输入完成跳到下一个输入框,这样的做法也能达到目的,不过需要更多的代码去维护这个规则,不够优雅。

目前的做法已经是我能想到最优的解决方案,如果你有更好的实现思路,还望不吝赐教。

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。