验证码防抖

This commit is contained in:
李志鹏
2025-10-13 10:27:07 +08:00
parent 39839a4d45
commit c3cd00dc1c

View File

@@ -1,85 +1,99 @@
<template> <template>
<div id="app"> <div id="app">
<div class="captcha"> <div class="captcha">
<input v-for="(c, index) in getCtData" :key="index" <input
v-for="(c, index) in getCtData"
:key="index"
type="text" type="text"
v-model="getCtData[index]" ref="input" v-model="getCtData[index]"
ref="input"
inputmode="numeric" inputmode="numeric"
pattern="[0-9]*" pattern="[0-9]*"
@input="e => {onInput(e.target.value, index)}" @input="(e) => onInput(e.target.value, index)"
@keydown="e => {onKeydown(e, index)}" @keydown="(e) => onKeydown(e, index)"
@keypress="e => {onKeypress(e)}" @keypress="(e) => onKeypress(e)"
@focus="onFocus" @focus="onFocus"
@pause="onPause"
:disabled="loading" :disabled="loading"
> />
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { defineComponent } from 'vue' import { defineComponent } from "vue";
export default defineComponent({ export default defineComponent({
props:['ct'], props: ["ct"],
data() { data() {
return { return {
loading: false, loading: false,
} timeout: null,
};
}, },
computed: { computed: {
getCtData(){ getCtData() {
return this.ct return this.ct;
}, },
ctSize() { ctSize() {
return this.getCtData.length; return this.getCtData.length;
}, },
cIndex() { cIndex() {
let i = this.getCtData.findIndex(item => item === ''); let i = this.getCtData.findIndex((item) => item === "");
i = (i + this.ctSize) % this.ctSize; i = (i + this.ctSize) % this.ctSize;
return i; return i;
}, },
lastCode() { lastCode() {
return this.getCtData[this.ctSize - 1]; return this.getCtData[this.ctSize - 1];
} },
}, },
watch: { watch: {
cIndex() { cIndex() {
this.resetCaret(); this.resetCaret();
}, },
lastCode(newVal,oldVal) { lastCode(newVal, oldVal) {
if (newVal && newVal != oldVal) { if (newVal && newVal != oldVal) {
this.$refs.input[this.ctSize - 1].blur(); this.$refs.input[this.ctSize - 1].blur();
this.sendCaptcha(); this.sendCaptcha();
} }
} },
}, },
mounted() { mounted() {
this.resetCaret(); this.resetCaret();
}, },
methods: { methods: {
onInput(val, index) { onInput(val, index) {
console.log('input',val,index) console.log("input", val, index);
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
console.log("input=>", val, index);
// val = val.replace(/[^0-9]/g, ''); // val = val.replace(/[^0-9]/g, '');
val = String(val).replace(/\D/g, ''); val = String(val).replace(/\D/g, "");
this.getCtData[index] = val this.getCtData[index] = val;
if (index == this.ctSize - 1) { if (index == this.ctSize - 1) {
this.getCtData[this.ctSize - 1] = val[0]; // 最后一个码,只允许输入一个字符。 this.getCtData[this.ctSize - 1] = val[0]; // 最后一个码,只允许输入一个字符。
} else if(val.length > 1) { } else if (val.length > 1) {
let i = index; let i = index;
for (i = index; i < this.ctSize && i - index < val.length; i++) { for (
i = index;
i < this.ctSize && i - index < val.length;
i++
) {
this.getCtData[i] = val[i]; this.getCtData[i] = val[i];
} }
this.resetCaret(); this.resetCaret();
}else if(!(val+'')){ } else if (!(val + "")) {
this.getCtData[index] = '' this.getCtData[index] = "";
} }
}, 10);
}, },
onPause() {},
// 重置光标位置。 // 重置光标位置。
resetCaret() { resetCaret() {
this.$refs.input[this.ctSize-1].focus(); this.$refs.input[this.ctSize - 1].focus();
}, },
onFocus() { onFocus() {
// 监听 focus 事件,将光标重定位到“第一个空白符的位置”。 // 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
let index = this.getCtData.findIndex(item => item === ''); let index = this.getCtData.findIndex((item) => item === "");
index = (index + this.ctSize) % this.ctSize; index = (index + this.ctSize) % this.ctSize;
this.$refs.input[index].focus(); this.$refs.input[index].focus();
}, },
@@ -92,60 +106,72 @@ export default defineComponent({
}, },
onKeydown(e, index) { onKeydown(e, index) {
// 处理删除键 // 处理删除键
if (e.key === 'Backspace' || e.key === 'Delete') { if (e.key === "Backspace" || e.key === "Delete") {
const val = e.target.value; const val = e.target.value;
if (val === '') { if (val === "") {
// 删除上一个input里的值并对其focus。 // 删除上一个input里的值并对其focus。
if (index > 0) { if (index > 0) {
this.getCtData[index - 1] = ''; this.getCtData[index - 1] = "";
this.$refs.input[index - 1].focus(); this.$refs.input[index - 1].focus();
} }
} }
} }
// 阻止其他非数字字符 // 阻止其他非数字字符
else if (e.key && !/[0-9]/.test(e.key) && !['Backspace', 'Delete', 'Tab', 'Enter', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) { else if (
e.key &&
!/[0-9]/.test(e.key) &&
![
"Backspace",
"Delete",
"Tab",
"Enter",
"ArrowLeft",
"ArrowRight",
"ArrowUp",
"ArrowDown",
].includes(e.key)
) {
e.preventDefault(); e.preventDefault();
} }
}, },
sendCaptcha() { sendCaptcha() {
let password = this.getCtData.map(item => item).join(''); let password = this.getCtData.map((item) => item).join("");
this.$emit('sendCaptcha',password) this.$emit("sendCaptcha", password);
}, },
reset() { reset() {
// 重置。一般是验证码错误时触发。 // 重置。一般是验证码错误时触发。
this.getCtData = this.getCtData.map(item => ''); this.getCtData = this.getCtData.map((item) => "");
this.resetCaret(); this.resetCaret();
} },
} },
}) });
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.captcha { .captcha {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
input { input {
width: 8.7rem; width: 8.7rem;
height: 8.7rem; height: 8.7rem;
border: 0.1rem solid #B4BED7; border: 0.1rem solid #b4bed7;
border-radius: 2rem; border-radius: 2rem;
text-align: center; text-align: center;
font-size: 2.4rem; font-size: 2.4rem;
line-height: 8.7rem; line-height: 8.7rem;
outline: none; outline: none;
} }
input:last-of-type { input:last-of-type {
margin-right: 0; margin-right: 0;
} }
input:disabled { input:disabled {
color: #000; color: #000;
background-color: #fff; background-color: #fff;
} }
.msg { .msg {
text-align: center; text-align: center;
} }
</style> </style>