Files
FiDA_Front/src/components/input-code.vue

104 lines
2.2 KiB
Vue
Raw Normal View History

2026-02-04 10:01:50 +08:00
<template>
<div class="input-code">
<input
ref="inputRef"
type="tel"
maxlength="1"
v-for="(v, i) in props.length"
:key="i"
v-model="code[i]"
@input="handleInput(i)"
@keydown.delete="handleDelete(i)"
@paste="handlePaste"
/>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, computed, watch, nextTick } from 'vue'
const emit = defineEmits(['submit', 'update:modelValue'])
const props = defineProps({
length: {
type: Number,
default: 6
}
})
const inputRef = ref('')
const code = ref([])
const codeStr = computed(() => code.value.join(''))
watch(codeStr, (newVal) => {
emit('update:modelValue', newVal)
})
const resetCode = (size) => {
code.value = []
for (let i = 0; i < size; i++) {
code.value.push('')
}
}
resetCode(props.length)
const handleInput = (index: number) => {
const value = code.value[index]
if (value) {
if (/[0-9]/.test(value)) {
code.value[index] = value
focusLast()
} else {
code.value[index] = ''
}
}
submit()
}
const handleDelete = (index: number) => {
if (code.value[index].length == 0) {
focusLast(-1)
}
}
const handlePaste = (e: ClipboardEvent) => {
const text = e.clipboardData?.getData('text')
if (text) {
const nums = text.match(/[0-9]/g) || []
if (nums.length === code.value.length) {
code.value = [...nums]
focusLast()
nextTick(submit)
}
}
}
// 聚焦最后一个没有输入的
const focusLast = (step = 0) => {
let index = code.value.findIndex((item) => !item) + step
index < 0 && (index = 0)
if (index >= 0 && index < props.length) {
inputRef.value[index]?.focus?.()
}
if (code.value.every((item) => item.length)) {
inputRef.value?.forEach((item) => item.blur?.())
}
}
const submit = () => {
if (codeStr.value.length === props.length) {
emit('submit', codeStr.value)
}
}
onMounted(() => {
focusLast()
})
</script>
<style lang="less" scoped>
.input-code {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
> input {
width: 7rem;
height: 7rem;
border-radius: 1rem;
border: 0.02rem solid #dfdfdf;
text-align: center;
margin: auto;
}
}
</style>