效果图

在这里插入图片描述

功能分解

  • 输入效果
  • 自动换焦
  • 如何删除
  • 接收paste事件

数据先行

  • 确定验证码位数 amout
  • 储存验证码的数组 code
  • 当前输入项的索引 currentIndex

布局

<template>
  <div class="ys-verification">
    <div class="input-wrapper" v-for="item in amount" :key="item">
      <input type="number"  @paste="handlePaste" title="code" v-focus="(item - 1) === currentIndex" maxlength="1" @input="handleInput($event,(item-1))" @keyup.delete="onDelete($event,(item-1))"  v-model="code[item-1]">
    </div>
  </div>
</template>

初始化code

  created () {
    this.code = new Array(this.amount).fill('')
  },

如何实现自动换焦

A: 采用自定义指令实现
正如模板代码中展示的那样,为每一个input绑定了一个v-focus指令

  directives: {
    focus: {
      componentUpdated: function (el, obj) {
        obj.value && el.focus()
      }
    }
  },

我们传入一个boolean值控制当前项是否获得焦点。
而Boolean值是由 (item - 1) === currentIndex 决定,因此我们只需要修改currentIndex的值便可以实现自动换焦.

在哪里修改currentIndex

可以给Input绑定一个input事件,输入一位数字之后就让currentIndex + 1

 methods: {
    handleInput (e, index) {
      this.currentIndex = index
      e.target.value = this.validateNumber(e.target.value)
      e.target.value !== '' && ++this.currentIndex
      !this.code.includes('') && this.$emit('onCompleted', this.code.join(''))
    },
      validateNumber (val) {
      return val.replace(/\D/g, '')
    },

怎么删除

我们监听键盘事件,使用vue的别名。删除之后退格。

@keyup.delete="onDelete($event,(item-1))"
//...
onDelete (e, index) {
      if (e.target.value === '') {
        this.currentIndex = index - 1 
      }
    },

粘贴

后来有了新需求,要求能够粘贴。
but,
我不能获取到Item的值,就很难受。
所以就没搞定,就简直粘贴了。
然而,有的手机还是能够粘贴

    handlePaste (e) {
      e.preventDefault()
    }

源码

<template>
  <div class="ys-verification">
    <div class="input-wrapper" v-for="item in amount" :key="item">
      <input type="number"  @paste="handlePaste" title="code" v-focus="(item - 1) === currentIndex" maxlength="1" @input="handleInput($event,(item-1))" @keyup.delete="onDelete($event,(item-1))"  v-model="code[item-1]">
    </div>
  </div>
</template>

<script>
export default {
  name: 'VerificationCodeInput',
  props: {
    amount: {
      type: Number,
      default: 4
    }
  },
  directives: {
    focus: {
      componentUpdated: function (el, obj) {
        obj.value && el.focus()
      }
    }
  },
  created () {
    this.code = new Array(this.amount).fill('')
  },
  methods: {
    handleInput (e, index) {
      this.currentIndex = index
      e.target.value = this.validateNumber(e.target.value)
      e.target.value !== '' && ++this.currentIndex
      !this.code.includes('') && this.$emit('onCompleted', this.code.join(''))
    },
    onDelete (e, index) {
      if (e.target.value === '') {
        this.currentIndex = index - 1
      }
    },
    validateNumber (val) {
      return val.replace(/\D/g, '')
    },
    handlePaste (e) {
      e.preventDefault()
    }
  },
  data () {
    return {
      code: [],
      currentIndex: 0
    }
  }
}
</script>

<style lang="less" scoped>
  .ys-verification{
    width:100%;
    display: flex;
    justify-content: space-around;

    .input-wrapper{
      border-bottom: 1px solid #D6D6D6;
      width: 15%;
      height: 0;
      padding-bottom:20%;
      position: relative;

      input{
        position: absolute;
        width: 100%;
        height: 100%;
        text-align: center;
        transition: all 0.3s;
        font-size: 7vw;
        color: #333333;
      }

    }

    input:focus{
      border-bottom: 1px solid #666666;
    }
  }
</style>

Logo

前往低代码交流专区

更多推荐