页面实现效果,实现原理是在卡片上方隐藏一个input输入框,聚集都会聚焦在input上,双向绑定数据,显示至卡片上。
一般移动端有组件,h5一般组件库都不支持这种,只能自己手写一个,样式也好控制
源码分享 这是vue3的 vue2自己转一下就行,原理都一样。
<!--
* @Author: Along
* @Date: 2024-06-06 09:58:37
* @Description: otp 验证输入框
-->
<template>
<div class="otp">
<div class="cardList">
<div
class="card"
v-for="i in 4"
:key="i"
:class="{
active:isFocus && ((isFocus && model.split('').length == 4 && i == 4) || model.length == i - 1)
}"
>
{{ list[i - 1] }}
</div>
</div>
<input
type="text"
:maxlength="4"
@keyup="onKeydown"
class="input"
@focus="isFocus = true"
@blur="isFocus = false"
ref="inputRef"
/>
</div>
</template>
<script setup>
import { ref, computed, watch ,nextTick} from 'vue'
let model = ref('')
// 监听 model 变化
watch(model, (newValue) => {
// 抛出事件
emit('update:modelValue', newValue)
})
let emit = defineEmits(['update:modelValue'])
// 根据 model 计算数组
let list = computed(() => {
let arr = ['', '', '', '']
if (!model.value) return arr
let newArr = model.value.split('')
for (let i = 0; i < newArr.length; i++) {
arr[i] = newArr[i] || ''
}
return arr
})
let onKeydown = (event) => {
if (event.key === 'Backspace' && model.value.length > 0) {
model.value = model.value.slice(0, -1)
}
// 只允许输入数字
if (!/^[0-9]*$/.test(event.key)) {
event.preventDefault()
} else {
// 最大四位
if (model.value.length < 4) {
model.value = model.value + event.key
}
}
}
let isFocus = ref(false)
let inputRef = ref(null)
// 默认聚焦
nextTick (() => {
inputRef.value.focus()
})
</script>
<style lang="less" scoped>
.otp {
margin-bottom: 20px;
position: relative;
height: 120px;
width: 484px;
input {
width: 100%;
height: 100%;
opacity: 0;
z-index: 2;
}
.cardList {
width: 100%;
height: 120px;
position: absolute;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 36px;
font-weight: 500;
color: #fff;
.card {
width: 100px;
height: 120px;
background: #ffffff;
border-radius: 8px;
border: 1px solid #d7d9db;
margin: 8px;
color: #2a2c2b;
font-weight: 500;
font-size: 64px;
color: #2a2c2b;
line-height: 120px;
transition: all 0.1;
text-align: center;
}
.active {
border: 1px solid #5683fb;
}
}
}
</style>