vue 实现6位数验证码框 兼容安卓和ios

304 阅读1分钟
<template>
  <div id="app">
  <div class="captcha">
    <input v-for="(c, index) in ct" :key="index"
      onkeyup="value=value.replace(/[^\d]/g,'')"
      oninput="value=value.replace(/[^\d]/g,'')"
      type="number" v-model="ct[index]" ref="input" 
      :style="{borderBottomColor: index <= cIndex ? '#333' : ''}"
      @input="e => {onInput(e.target.value, index)}" 
      @keydown.delete="e=>{onKeydown(e.target.value, index)}"
      @focus="onFocus"
      :disabled="loading"
      >
  </div>
  <p>{{msg}}</p>
</div>
</template>

<script>
export default {
  name: '',
  data() {
    return {
      ct: ['', '', '', '', '', ''],
      loading: false,
      msg: '',
    }
  },
  computed: {
    ctSize() {
      return this.ct.length;
    },
    cIndex() {
      let i = this.ct.findIndex(item => item === '');
      i = (i + this.ctSize) % this.ctSize;
      return i;
    },
    lastCode() {
      return this.ct[this.ctSize - 1];
    }
  },
  watch: {
    cIndex() {
      this.resetCaret();
    },
    lastCode(val) {
      if (val) {
        console.log('this.ctSize', this.ctSize)
        this.$refs.input[this.ctSize - 1].blur();
        this.sendCaptcha();
      }
    }
  },
  mounted() {
    this.resetCaret();
  },
  methods: {
    onInput(val, index) {
      this.msg = ''
      val = val.replace(/\s/g, '');
      if (index == this.ctSize - 1) {
        this.ct[this.ctSize - 1] = val[0];   // 最后一个码,只允许输入一个字符。
      } else if(val.length > 1) {
        let i = index;
        for (i = index; i < this.ctSize && i - index < val.length; i++) {
          this.ct[i] = val[i];
        }
        this.resetCaret();
      }
    },
    // 重置光标位置。
    resetCaret() {
      this.$refs.input[this.ctSize-1].focus();
    },
    onFocus() {
      // 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
      let index = this.ct.findIndex(item => item === '');
      index = (index + this.ctSize) % this.ctSize;
      console.log(this.$refs.input)
      this.$refs.input[index].focus();
    },
    onKeydown(val, index) {
      if (val === '') {
        // 删除上一个input里的值,并对其focus。
        if (index > 0) {
          this.ct[index - 1] = '';
          this.$refs.input[index - 1].focus();
        }
      }
    },
    sendCaptcha() {
      console.log();
      this.msg = `发送验证码到服务器:${this.ct.join('')}`;
      // 此时无法操作 input。。
      this.loading = true;
      setTimeout(() => {
        this.msg = ('验证码错误')
        this.loading = false;
        this.$nextTick(() => {
          this.reset();
        })
      }, 3000)
    },

    reset() {
      // 重置。一般是验证码错误时触发。
      this.ct = this.ct.map(item => '');
      this.resetCaret();
    }
  }
}
</script>

<style lang="scss" scoped>
.captcha {
  display: flex;
  justify-content: center;
  margin-top: 2.5rem;
}
input {
  margin-right: 1.25rem;
  width: 1.25rem;
  text-align: center;
  border: none;
  border-bottom: .0625rem solid #eee;
  font-size: .75rem;
  outline: none;
}
input:last-of-type {
  margin-right: 0;
}
input:disabled {
  color: #000;
  background-color: #fff;
}
.msg {
  text-align: center;
}
</style>