vue 6位 验证码输入组件

完全和单输入框一样的操作,甚至可以插入覆盖:

1,限制输入数字

2,正常输入

3,backspace删除

4,paste任意位置粘贴输入

5,光标选中一个数字,滚轮可以微调数字大小,限制0-9

6,123|456 自动覆盖光标后输入的字符,此时光标在3后,继续输入111,会得到123111,而不用手 动删除456

7,封装成vue单文件组件,方便任意调用。

效果:

页面模板代码

<template>
  <div class="input-box">
    <div class="input-content" @keydown="keydown" @keyup="keyup" @paste="paste" @mousewheel="mousewheel" @input="inputEvent">
      <input max="9" min="0" maxlength="1" data-index="0" vmodel.trim.number="input[0]" type="number" ref="firstinput"/>
      <input max="9" min="0" maxlength="1" data-index="1" vmodel.trim.number="input[1]" type="number"/>
      <input max="9" min="0" maxlength="1" data-index="2" vmodel.trim.number="input[2]" type="number"/>
      <input max="9" min="0" maxlength="1" data-index="4" vmodel.trim.number="input[4]" type="number"/>
      <input max="9" min="0" maxlength="1" data-index="5" vmodel.trim.number="input[5]" type="number"/>
    </div>
  </div>
</template>

JS 逻辑代码

  1 <script>
  2 export default {
  3   data() {
  4     return {
  5       pasteResult: [],
  6       code: ''
  7     }
  8   },
  9   // props: ['code'],
 10   computed: {
 11     input() {
 12       if (this.code && Array.isArray(this.code) && this.code.length === 6) {
 13         return this.code
 14       } else if (/^\d{6}$/.test(this.code.toString())) {
 15         return this.code.toString().split('')
 16       } else if (this.pasteResult.length === 6) {
 17         return this.pasteResult
 18       } else {
 19         return new Array(6)
 20       }
 21     },
 22   },
 23   methods: {
 24     // 解决一个输入框输入多个字符
 25     inputEvent(e) {
 26       var index = e.target.dataset.index * 1
 27       var el = e.target
 28       el.value = el.value
 29         .replace(/Digit|Numpad/i, '')
 30         // .replace(/1/g, '')
 31         .slice(0, 1)
 32       this.$set(this.input, index, el.value)
 33     },
 34     keydown(e) {
 35       var index = e.target.dataset.index * 1
 36       var el = e.target
 37       if (e.key === 'Backspace') {
 38         if (this.input[index].length > 0) {
 39           this.$set(this.input, index, '')
 40         } else {
 41           if (el.previousElementSibling) {
 42             el.previousElementSibling.focus()
 43             this.$set(this.input, index - 1, '')
 44           }
 45         }
 46       } else if (e.key === 'Delete') {
 47         if (this.input[index].length > 0) {
 48           this.$set(this.input, index, '')
 49         } else {
 50           if (el.nextElementSibling) {
 51             this.$set(this.input, (index = 1), '')
 52           }
 53         }
 54         if (el.nextElementSibling) {
 55           el.nextElementSibling.focus()
 56         }
 57       } else if (e.key === 'Home') {
 58         el.parentElement.children[0] && el.parentElement.children[0].focus()
 59       } else if (e.key === 'End') {
 60         el.parentElement.children[this.input.length - 1] &&
 61           el.parentElement.children[this.input.length - 1].focus()
 62       } else if (e.key === 'ArrowLeft') {
 63         if (el.previousElementSibling) {
 64           el.previousElementSibling.focus()
 65         }
 66       } else if (e.key === 'ArrowRight') {
 67         if (el.nextElementSibling) {
 68           el.nextElementSibling.focus()
 69         }
 70       } else if (e.key === 'ArrowUp') {
 71         if (this.input[index] * 1 < 9) {
 72           this.$set(this.input, index, (this.input[index] * 1 + 1).toString())
 73         }
 74       } else if (e.key === 'ArrowDown') {
 75         if (this.input[index] * 1 > 0) {
 76           this.$set(this.input, index, (this.input[index] * 1 - 1).toString())
 77         }
 78       }
 79     },
 80     keyup(e) {
 81       var index = e.target.dataset.index * 1
 82       var el = e.target
 83       // 解决输入e的问题
 84       el.value = el.value
 85         .replace(/Digit|Numpad/i, '')
 86         // .replace(/1/g, '')
 87         .slice(0, 1)
 88       if (/Digit|Numpad/i.test(e.code)) {
 89         // 必须在这里符直,否则输入框会是空值
 90         this.$set(this.input, index, e.code.replace(/Digit|Numpad/i, ''))
 91         el.nextElementSibling && el.nextElementSibling.focus()
 92         if (index === 5) {
 93           if (this.input.join('').length === 6) {
 94             document.activeElement.blur()
 95             this.$emit('complete', this.input)
 96           }
 97         }
 98       } else {
 99         if (this.input[index] === '') {
100           this.$set(this.input, index, '')
101         }
102       }
103     },
104     mousewheel(e) {
105       var index = e.target.dataset.index
106       if (e.wheelDelta > 0) {
107         if (this.input[index] * 1 < 9) {
108           this.$set(this.input, index, (this.input[index] * 1 + 1).toString())
109         }
110       } else if (e.wheelDelta < 0) {
111         if (this.input[index] * 1 > 0) {
112           this.$set(this.input, index, (this.input[index] * 1 - 1).toString())
113         }
114       } else if (e.key === 'Enter') {
115         if (this.input.join('').length === 6) {
116           document.activeElement.blur()
117           this.$emit('complete', this.input)
118         }
119       }
120     },
121     paste(e) {
122       // 当进行粘贴时
123       e.clipboardData.items[0].getAsString((str) => {
124         if (str.toString().length === 6) {
125           this.pasteResult = str.split('')
126           document.activeElement.blur()
127           this.$emit('complete', this.input)
128           this.pasteResult = []
129         } else {
130           // 如果粘贴内容不合规,清除所有内容
131           this.input[0] = new Array(6)
132         }
133       })
134     },
135   },
136   mounted() {
137     // 等待dom渲染完成,在执行focus,否则无法获取到焦点
138     this.$nextTick(() => {
139       this.$refs.firstinput.focus()
140     })
141   },
142 }
143 </script>

CSS 样式代码

<style scoped lang="scss">
.input-box {
  .input-content {
    width: 512px;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;

    input {
      color: inherit;
      font-family: inherit;
      border: 0;
      outline: 0;
      border-bottom: 1px solid #919191;
      height: 60px;
      width: 60px;
      font-size: 44px;
      text-align: center;
    }
  }

  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }

  input::-webkit-outer-spin-button,
  input::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }
}
</style>

 

posted @ 2020-11-10 16:43  吕少少  阅读(1291)  评论(0编辑  收藏  举报