Files
aida_front/src/component/LoginPage/verificationCodeInput.vue
2026-01-14 16:56:39 +08:00

183 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div id="app">
<div class="captcha">
<input
v-for="(c, index) in getCtData"
:key="index"
type="text"
v-model="getCtData[index]"
ref="input"
inputmode="numeric"
pattern="[0-9]*"
@input="(e) => onInput(e.target.value, index)"
@keydown="(e) => onKeydown(e, index)"
@keypress="(e) => onKeypress(e)"
@focus="onFocus"
@pause="onPause"
:disabled="loading"
/>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
props: ["ct"],
data() {
return {
loading: false,
timeout: null,
};
},
computed: {
getCtData() {
return this.ct;
},
ctSize() {
return this.getCtData.length;
},
cIndex() {
let i = this.getCtData.findIndex((item) => item === "");
i = (i + this.ctSize) % this.ctSize;
return i;
},
lastCode() {
return this.getCtData[this.ctSize - 1];
},
},
watch: {
cIndex() {
this.resetCaret();
},
lastCode(newVal, oldVal) {
if (newVal && newVal != oldVal) {
this.$refs.input[this.ctSize - 1].blur();
this.sendCaptcha();
}
},
},
mounted() {
this.resetCaret();
},
methods: {
onInput(val, index) {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
// val = val.replace(/[^0-9]/g, '');
val = String(val).replace(/\D/g, "");
this.getCtData[index] = val;
if (index == this.ctSize - 1) {
this.getCtData[this.ctSize - 1] = val[0]; // 最后一个码,只允许输入一个字符。
} else if (val.length > 1) {
let i = index;
for (
i = index;
i < this.ctSize && i - index < val.length;
i++
) {
this.getCtData[i] = val[i];
}
this.resetCaret();
} else if (!(val + "")) {
this.getCtData[index] = "";
}
}, 10);
},
onPause() {},
// 重置光标位置。
resetCaret() {
this.$refs.input[this.ctSize - 1].focus();
},
onFocus() {
// 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
let index = this.getCtData.findIndex((item) => item === "");
index = (index + this.ctSize) % this.ctSize;
this.$refs.input[index].focus();
},
onKeypress(e) {
// 只允许输入数字0-9
const char = String.fromCharCode(e.which);
if (!/[0-9]/.test(char)) {
e.preventDefault();
}
},
onKeydown(e, index) {
// 处理删除键
if (e.key === "Backspace" || e.key === "Delete") {
const val = e.target.value;
if (val === "") {
// 删除上一个input里的值并对其focus。
if (index > 0) {
this.getCtData[index - 1] = "";
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)
) {
e.preventDefault();
}
},
sendCaptcha() {
let password = this.getCtData.map((item) => item).join("");
this.$emit("sendCaptcha", password);
},
reset() {
// 重置。一般是验证码错误时触发。
this.getCtData = this.getCtData.map((item) => "");
this.resetCaret();
},
},
});
</script>
<style scoped lang="less">
.captcha {
display: flex;
justify-content: space-between;
}
input {
width: 8.7rem;
height: 8.7rem;
border: 0.1rem solid #b4bed7;
border-radius: 2rem;
text-align: center;
font-size: 2.4rem;
line-height: 8.7rem;
outline: none;
@media (max-width: 767px) {
border-radius: .7rem;
width: 3.5rem;
height: 3.5rem;
font-size: 1.8rem;
line-height: 3.5rem;
}
}
input:last-of-type {
margin-right: 0;
}
input:disabled {
color: #000;
background-color: #fff;
}
.msg {
text-align: center;
}
</style>