在 Vue 中簡(jiǎn)單實(shí)現(xiàn)一個(gè) 6 個(gè)輸入框的驗(yàn)證碼組件

來(lái)源 | https://segmentfault.com/a/1190000023041401
1,限制輸入數(shù)字
2,正常輸入
3,backspace刪除
4,paste任意位置粘貼輸入
5,光標(biāo)選中一個(gè)數(shù)字,滾輪可以微調(diào)數(shù)字大小,限制0-9
6,123|456 自動(dòng)覆蓋光標(biāo)后輸入的字符,此時(shí)光標(biāo)在3后,繼續(xù)輸入111,會(huì)得到123111,而不用手動(dòng)刪除456
7,封裝成vue單文件組件,方便任意調(diào)用。

模板代碼
<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>
實(shí)現(xiàn)了鍵盤的keydown/keyup/paste/input和鼠標(biāo)滾輪mousewheel事件
使用了6個(gè)輸入框的方案來(lái)實(shí)現(xiàn)。
樣式部分:使用了scss模式
scoped>{{width: 512px;height: 60px;display: flex;: center;: space-between;input {color: inherit;: inherit;border: 0;outline: 0;: 1px solid #919191;height: 60px;width: 60px;: 44px;: center;}}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {appearance: none;margin: 0;}}</style>
具體實(shí)現(xiàn)邏輯:主要實(shí)現(xiàn)以上幾個(gè)鍵盤事件操作。
<script>export default {data() {return {// 存放粘貼進(jìn)來(lái)的數(shù)字pasteResult: [],};},props: ['code'],computed: {input() {// code 是父組件傳進(jìn)來(lái)的默認(rèn)值,必須是6位長(zhǎng)度的數(shù)組,這里就不再做容錯(cuò)判斷處理// 最后空數(shù)組是默認(rèn)值return this.code || this.pasteResult.length === 6 ? this.pasteResult : ['', '', '', '', '', '']}},methods: {// 解決一個(gè)輸入框輸入多個(gè)字符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;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) {// 當(dāng)進(jìn)行粘貼時(shí)e.clipboardData.items[0].getAsString(str => {if (str.toString().length === 6) {this.pasteResult = str.split('');document.activeElement.blur();this.$emit('complete', this.input);}})}},mounted() {// 等待dom渲染完成,在執(zhí)行focus,否則無(wú)法獲取到焦點(diǎn)this.$nextTick(() => {this.$refs.firstinput.focus()})},}</script>
如果你發(fā)現(xiàn)了bug,或者有優(yōu)化空間,歡迎你的指正和建議。我會(huì)隨時(shí)更新到原代碼當(dāng)中,分享給大家。
本文完~

評(píng)論
圖片
表情
