vue实现一个6个输入框的验证码输入组件

image.png

要实现的功能:

完全和单输入框一样的操作,甚至可以插入覆盖:
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" v-model.trim.number="input[0]" type="number"

ref="firstinput"/>

<input max="9" min="0" maxlength="1" data-index="1" v-model.trim.number="input[1]" type="number"/>

<input max="9" min="0" maxlength="1" data-index="2" v-model.trim.number="input[2]" type="number"/>

<input

<input max="9" min="0" maxlength="1" data-index="4" v-model.trim.number="input[4]" type="number"/>

<input max="9" min="0" maxlength="1" data-index="5" v-model.trim.number="input[5]" type="number"/>

</div>

</div>

</template>

实现了键盘的keydown/keyup/paste/input和鼠标滚轮mousewheel事件
使用了6个输入框的方案来实现。

样式部分:使用了scss模式

<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;

}

}

</style>

具体实现逻辑:主要实现以上几个键盘事件操作。

<script>

export default {

data() {

return {

// 存放粘贴进来的数字

pasteResult: [],

};

},

props: ['code'],

computed: {

input() {

// 计算输入框的值

if (this.code && Array.isArray(this.code) && this.code.length === 6) {

return this.code;

} else if (/^d{6}$/.test(this.code.toString())) {

return this.code.toString().split('');

} else if (this.pasteResult.length === 6) {

return this.pasteResult;

} else {

return new Array(6);

}

}

},

methods: {

// 解决一个输入框输入多个字符

inputEvent(e) {

var index = e.target.dataset.index * 1;

var el = e.target;

this.$set(this.input, index, el.value.slice(0, 1))

},

keydown(e) {

var index = e.target.dataset.index * 1;

var el = e.target;

if (e.key === 'Backspace') {

if (this.input[index].length > 0) {

this.$set(this.input, index, '')

} else {

if (el.previousElementSibling) {

el.previousElementSibling.focus()

this.$set(this.input, index - 1, '')

}

}

} else if (e.key === 'Delete') {

if (this.input[index].length > 0) {

this.$set(this.input, index, '')

} else {

if (el.nextElementSibling) {

this.$set(this.input, index = 1, '')

}

}

if (el.nextElementSibling) {

el.nextElementSibling.focus()

}

} else if (e.key === 'Home') {

el.parentElement.children[0] && el.parentElement.children[0].focus()

} else if (e.key === 'End') {

el.parentElement.children[this.input.length - 1] && el.parentElement.children[this.input.length - 1].focus()

} else if (e.key === 'ArrowLeft') {

if (el.previousElementSibling) {

el.previousElementSibling.focus()

}

} else if (e.key === 'ArrowRight') {

if (el.nextElementSibling) {

el.nextElementSibling.focus()

}

} else if (e.key === 'ArrowUp') {

if (this.input[index] * 1 < 9) {

this.$set(this.input, index, (this.input[index] * 1 + 1).toString());

}

} else if (e.key === 'ArrowDown') {

if (this.input[index] * 1 > 0) {

this.$set(this.input, index, (this.input[index] * 1 - 1).toString());

}

}

},

keyup(e) {

var index = e.target.dataset.index * 1;

var el = e.target;

// 解决输入e和无法删除e的问题 感谢一楼网友 https://segmentfault.com/u/nanzk8fl 的指正

el.value=el.value.replace(/1/g,'');

if (/Digit|Numpad/i.test(e.code)) {

this.$set(this.input, index, e.code.replace(/Digit|Numpad/i, ''));

el.nextElementSibling && el.nextElementSibling.focus();

if (index === 5) {

if (this.input.join('').length === 6) {

document.activeElement.blur();

this.$emit('complete', this.input);

}

}

} else {

if (this.input[index] === '') {

this.$set(this.input, index, '');

}

}

},

mousewheel(e) {

var index = e.target.dataset.index;

if (e.wheelDelta > 0) {

if (this.input[index] * 1 < 9) {

this.$set(this.input, index, (this.input[index] * 1 + 1).toString());

}

} else if (e.wheelDelta < 0) {

if (this.input[index] * 1 > 0) {

this.$set(this.input, index, (this.input[index] * 1 - 1).toString());

}

} else if (e.key === 'Enter') {

if (this.input.join('').length === 6) {

document.activeElement.blur();

this.$emit('complete', this.input);

}

}

},

paste(e) {

// 当进行粘贴时

e.clipboardData.items[0].getAsString(str => {

if (str.toString().length === 6) {

this.pasteResult = str.split('');

document.activeElement.blur();

this.$emit('complete', this.input);

// 恢复缓冲区

this.pasteResult = [];

}

else {

// 如果粘贴内容不合规,清除所有内容

this.input = new Array(6)

}

})

}

},

mounted() {

// 等待dom渲染完成,在执行focus,否则无法获取到焦点

this.$nextTick(() => {

this.$refs.firstinput.focus()

})

},

}

</script>

如果你发现了bug,或者有优化空间,欢迎你的指正和建议。我会随时更新到原代码当中,分享给大家。

以上是 vue实现一个6个输入框的验证码输入组件 的全部内容, 来源链接: utcz.com/a/28275.html

回到顶部