vue3实现输入框短信验证码功能---全网始祖
组件功能分析
1.按键删除,清空当前input,并跳转prevInput & 获取焦点,按键delete,清空当前input,并跳转nextInput & 获取焦点。按键Home/End键,焦点跳转first/最后一个input输入框。ArrowLeft/ArrowRight键点击后跳转上一个/下一个输入框获取焦点。
2.判断按键为数字,则取第一个数字,然后跳转下一个input输入框获取焦点,如果为最后一个,则失去焦点,交互结束。
3.粘贴功能。通过el.clipboardData获取粘贴内容,判断是否为4/6位粘贴内容。是则赋值给页面Input,双向绑定一个数组即可。否则置为空。
代码展示
<template>
<div class="g-remove-check-code">
<p class="g-remove-check-code_title">发送验证码</p>
<div class="g-remove-check-code">
<p class="g-remove-check-code_title">
请输入短信验证码以验证您的身份
</p>
<div
class="g-remove-check-code_content"
@keyup="fnCheckCodeKeyup"
@keydown="fnCheckCodeKeydown"
@paste="fnCheckCodeKeyPaste"
@input="fnCheckCodeInputEvent"
>
<input :class="{'g-code-input_color': aCheckCodeInputComputed[0] !== ''}" max="9" min="0" maxlength="1" data-index="0" v-model.trim.number="aCheckCodeInputComputed[0]" type="text" ref="firstInputRef" />
<input :class="{'g-code-input_color': aCheckCodeInputComputed[1] !== ''}" max="9" min="0" maxlength="1" data-index="1" v-model.trim.number="aCheckCodeInputComputed[1]" type="text" />
<input :class="{'g-code-input_color': aCheckCodeInputComputed[2] !== ''}" max="9" min="0" maxlength="1" data-index="2" v-model.trim.number="aCheckCodeInputComputed[2]" type="text" />
<input :class="{'g-code-input_color': aCheckCodeInputComputed[3] !== ''}" max="9" min="0" maxlength="1" data-index="3" v-model.trim.number="aCheckCodeInputComputed[3]" type="text" />
</div>
</div>
<div class="btn-box">
<button
:disabled="!turnOff"
content-text="下一步"
@clickEvent="enter"
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { defineComponent, ref, onMounted, onUnmounted, reactive, computed, getCurrentInstance, inject } from "vue";
let aCheckCodeInput = ref(["", "", "", ""]) // 存储输入验证码内容
let aCheckCodePasteResult = ref([])
const turnOff = computed(() => {
return aCheckCodeInputComputed.value.filter((v) => !!v)?.length >= 4;
});
onUnmounted(() => {
clearInterval(timer.value);
})
const enter = async () => {
console.log("your code",aCheckCodeInputComputed.value.join("").toUpperCase())
}
const aCheckCodeInputComputed = computed(() => {
if(aCheckCodePasteResult.value.length === 4) {
return aCheckCodePasteResult.value;
} else if (aCheckCodeInput.value && Array.isArray(aCheckCodeInput.value) && aCheckCodeInput.value.length === 4) {
return aCheckCodeInput.value;
} else if (/^\d{4}$/.test(aCheckCodeInput.value.toString())) {
return aCheckCodeInput.value.toString().split("");
} else {
return new Array(4);
}
})
// 输入验证码,更新验证码数据
const fnCheckCodeKeyup = (e: any) => {
let index = e?.target?.dataset.index * 1;
let el = e.target;
// 解决输入e的问题
el.value = el.value
.replace(/Digit|Numpad/i, "")
.slice(0, 1);
if (/Digit|Numpad/i.test(e.code)) {
// 必须在这里赋值,否则输入框会是空值
aCheckCodeInput.value.splice(index, 1, e.code.replace(/Digit|Numpad/i, ""));
el.nextElementSibling && el.nextElementSibling.focus();
if (index === 3) {
if (aCheckCodeInput.value.join("").length === 4) (document.activeElement as any).blur();
}
}
}
// 输入验证码,检测位置变化
const fnCheckCodeKeydown = (e: any) =>{
let index = e?.target?.dataset?.index * 1;
let el = e.target;
if (e?.key === "Backspace") {
if (aCheckCodeInput.value[index].length > 0) {
aCheckCodeInput.value.splice(index, 1, "");
} else {
if (el.previousElementSibling) {
el.previousElementSibling.focus();
aCheckCodeInput.value[index - 1] = "";
}
}
} else if(e?.key === "Delete") {
if (aCheckCodeInput.value[index].length > 0) {
aCheckCodeInput.value.splice(index, 1, "");
} else {
if(el.nextElementSibling) {
el.nextElementSibling.focus();
aCheckCodeInput.value[++index] = "";
}
}
} else if (e?.key === "Home") {
el?.parentElement?.children[0] && el.parentElement.children[0].focus();
} else if (e?.key === "End") {
el?.parentElement?.children[aCheckCodeInput.value.length - 1] &&
el?.parentElement?.children[aCheckCodeInput.value.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 === 'Enter') {
this.doActive()
}
}
// 输入验证码,解决一个输入框输入多个字符的问题
const fnCheckCodeInputEvent = (e: any) => {
let index = e?.target?.dataset?.index * 1;
let el = e?.target;
el.value = el?.value
.replace(/Digit|Numpad/i, "")
.slice(0, 1);
aCheckCodeInput.value[index] = el.value;
}
// 验证码粘贴
const fnCheckCodeKeyPaste = (e: any) =>{
e?.clipboardData?.items[0].getAsString((str: string) => {
if (str.toString().length === 4) {
aCheckCodePasteResult.value = str.split("") as any;
(document.activeElement as any).blur();
aCheckCodeInput.value = aCheckCodeInputComputed.value;
aCheckCodePasteResult.value = [];
} else {
// 如果粘贴内容不合规,清除所有内容
aCheckCodeInput.value = ["", "", "", ""];
}
});
}
</script>
<style scoped lang="scss">
.g-remove-check-code {
width: 100%;
padding: 4px 0 8px 0;
}
.g-remove-check-code .g-remove-check-code_title {
font-size: 14px;
color: #666;
}
.g-remove-check-code .g-remove-check-code_content {
display: flex;
justify-content: space-between;
align-items: center;
width: 400px;
padding: 28px 0 28px 0;
margin: 0 auto;
}
.g-remove-check-code .g-remove-check-code_content input {
width: 50px;
height: 50px;
font-size: 36px;
text-align: center;
border: none;
outline: none;
border: solid 1px rgba(187, 187, 187, 100);
border-radius: 4px;
-moz-appearance: textfield;
}
.g-remove-check-code .g-remove-check-code_content input.g-code-input_color {
border-color: #5290FF;
}
.g-remove-check-code .g-remove-check-code_content input::-webkit-outer-spin-button,
.g-remove-check-code .g-remove-check-code_content input::-webkit-inner-spin-button {
appearance: none;
margin: 0;
}
.g-remove-check-code .g-remove-check-code_tip {
font-size: 14px;
color: #999;
text-align: center;
}
</style>
效果展示