要實現的功能:css
徹底和單輸入框同樣的操做,甚至能夠插入覆蓋:
1,限制輸入數字
2,正常輸入
3,backspace刪除
4,paste任意位置粘貼輸入
5,光標選中一個數字,滾輪能夠微調數字大小,限制0-9
6,123|456 自動覆蓋光標後輸入的字符,此時光標在3後,繼續輸入111,會獲得123111,而不用手動刪除456
7,封裝成vue單文件組件,方便任意調用。vue
模板代碼git
<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個輸入框的方案來實現。web
樣式部分:使用了scss模式app
<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>
具體實現邏輯:主要實現以上幾個鍵盤事件操做。dom
<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,或者有優化空間,歡迎你的指正和建議。我會隨時更新到原代碼當中,分享給你們。flex