mrr.sj.front/components/input-box/input-box.vue

119 lines
2.0 KiB
Vue
Raw Permalink Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="code-box">
<view
v-for="(item, idx) in codeLength"
:key="idx"
:class="['code-cell', idx === currentIndex ? 'active' : '', code[idx] ? 'filled' : '']">
<text v-if="code[idx]">{{ code[idx] }}</text>
</view>
<!-- 隐藏真实输入框 -->
<input
class="real-input"
type="number"
:maxlength="codeLength"
v-model="inputValue"
:focus="true"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
cursor-spacing="100"
ref="realInput" />
</view>
</template>
<script>
export default {
name:"input-box",
props: {
codeLength: {
type: Number,
default: 4
}
},
data() {
return {
inputValue: '',
};
},
computed: {
code() {
return this.inputValue.split('').slice(0, this.codeLength)
},
currentIndex() {
return this.inputValue.length
}
},
methods: {
onInput(e) {
let val = e.detail.value.replace(/[^0-9]/g, '').slice(0, this.codeLength)
this.inputValue = val
this.$emit('input', val)
if (val.length === this.codeLength) {
this.$emit('confirm', val)
}
},
onFocus() {
this.isFocus = true
this.inputValue = ''
},
onBlur() {
this.isFocus = false
},
onConfirm() {
if (this.inputValue.length === this.codeLength) {
this.$emit('confirm', this.inputValue);
}
},
close() {
this.$emit('close')
}
}
}
</script>
<style lang="scss" scoped>
.code-box {
flex-direction: row;
display: flex;
justify-content: center;
margin-bottom: 48rpx;
position: relative;
.code-cell {
width: 72rpx;
height: 72rpx;
border: 2rpx solid #eee;
border-radius: 16rpx;
margin-right: 24rpx;
font-size: 40rpx;
color: #ff4d8d;
background: #fff;
text-align: center;
line-height: 72rpx;
box-sizing: border-box;
transition: border-color 0.2s;
&.active {
border-color: #ff4d8d;
}
&.filled {
border-color: #ff4d8d;
}
&:last-child {
margin-right: 0;
}
}
.real-input {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
z-index: 2;
}
}
</style>