要实现的功能:
完全和单输入框一样的操作,甚至可以插入覆盖:
1,限制输入数字
2,正常输入
3,backspace删除
4,paste任意位置粘贴输入
5,光标选中一个数字,滚轮可以微调数字大小,限制0-9
6,123|456 自动覆盖光标后输入的字符,此时光标在3后,继续输入111,会得到123111,而不用手动删除456
7,封装成vue单文件组件,方便任意调用。
模板代码
<template>
<div>
<div @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;
el.value = el.value.replace(/Digit|Numpad/i, '').replace(/1/g, '').slice(0, 1);
this.$set(this.input, index, el.value)
},
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的问题
el.value = el.value.replace(/Digit|Numpad/i, '').replace(/1/g, '').slice(0, 1);
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[0] = new Array(6)
}
})
}
},
mounted() {
// 等待dom渲染完成,在执行focus,否则无法获取到焦点
this.$nextTick(() => {
this.$refs.firstinput.focus()
})
},
}
</script>
如果你发现了bug,或者有优化空间,欢迎你的指正和建议。我会随时更新到原代码当中,分享给大家。
热门评论:
-
nanzk8fL 2020-6-29 8:58 回复:
哈哈,好漂亮,功能也好全。另外我发现一个不知道能不能优化的地方,就是我按键盘上的字母e键,能输入eeeee字,而且貌似清理不了
- .d ↩
jsoncode 2020-6-29 9:35 回复:nanzk8fL
@nanzk8fL[nanzk8fl] 你提到的问题已经更新到文章里了,非常感谢反馈。
-
coderOG 2020-6-29 12:18 回复:
前几个为空从第二或第三开始输入时,最后一位可以无限输,失焦时才正确,这块可以优化下。。
-
Letme 2020-6-30 10:58 回复:
输入控件中间空一位或者2位,最后一位就可以输入大于1的数多个,只有在失去焦点的时候才正常
-
Cho Rong 2020-7-10 5:52 回复:
bug好多。手机端输入不了,PC端输1不显示要再输一个数字才行,而且可以选中非第一位的输入框。。
-
beelzahan 2021-8-3 3:58 回复:
粘贴功能只能粘贴第一位吗
jsoncode 2021-8-31 5:55 回复:beelzahan
4,paste任意位置粘贴输入,如果你发现bug,随时再反馈哦。
-
其实不奇怪 2021-8-31 5:53 回复:
你好 我刚从原生转h5,需要去掉数字的限制,我们有字母和数字,我单纯改了输入框,字符不能连续输入
柒kZBc6 2021-9-6 10:50 回复:
PC端输入太快会有空的
-
其实不奇怪 2021-9-9 2:10 回复:
大佬,我又来了,IE浏览器发现一个bug,特来提交,哈哈
https://developer.mozilla.org...jsoncode 2021-11-1 11:06 回复:其实不奇怪
我现在电脑都没有ie浏览器了,ie还是老老实实用一个输入框吧 :D
千万分之一 2021-10-25 5:09 回复:
可以