117 lines
2.4 KiB
Vue
117 lines
2.4 KiB
Vue
<template>
|
|
<el-form-item class="captcha-container" label="请输入验证码" label-position="top" :prop="prop">
|
|
<el-input-otp v-model="captchaValue" :length="length" integer @change="handleChange" @finish="handleFinish" size="large" />
|
|
<el-button type="primary" class="form-btn" v-if="showSendButton" @click="sendCode" :disabled="isCounting">{{
|
|
isCounting ? `${countdown}s后重新获取` : '发送验证码' }}</el-button>
|
|
</el-form-item>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, watch, toRefs } from 'vue'
|
|
|
|
defineOptions({
|
|
name: 'Captcha'
|
|
})
|
|
|
|
const props = defineProps({
|
|
modelValue: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
length: {
|
|
type: Number,
|
|
default: 6
|
|
},
|
|
showSendButton: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
sendState: {
|
|
type: Object,
|
|
default: () => ({
|
|
isCounting: false,
|
|
countdown: 0,
|
|
})
|
|
},
|
|
prop: {
|
|
type: String,
|
|
default: 'code' // 和父组件rules中的key一致
|
|
},
|
|
})
|
|
|
|
// 本地倒计时状态
|
|
const isCounting = ref(false)
|
|
const countdown = ref(0)
|
|
|
|
// 监听外部 sendState 变化
|
|
watch(
|
|
() => props.sendState,
|
|
(newVal) => {
|
|
console.log('监听 倒数 变化');
|
|
|
|
isCounting.value = newVal.isCounting
|
|
countdown.value = newVal.countdown
|
|
},
|
|
{ deep: true, immediate: true }
|
|
)
|
|
|
|
const { showSendButton } = toRefs(props)
|
|
const emit = defineEmits(['update:modelValue', 'change', 'finish', 'sendCode'])
|
|
|
|
// 使用 el-input-otp 的值(字符串形式)
|
|
const captchaValue = ref('')
|
|
|
|
// 监听外部 modelValue 变化
|
|
watch(
|
|
() => props.modelValue,
|
|
(newVal) => {
|
|
if (newVal !== captchaValue.value) {
|
|
captchaValue.value = newVal || '';
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
// 值变化时同步到父组件
|
|
const handleChange = (val: string) => {
|
|
emit('update:modelValue', val);
|
|
emit('change', val);
|
|
}
|
|
|
|
// 输入完成时触发
|
|
const handleFinish = (val: string) => {
|
|
emit('update:modelValue', val);
|
|
emit('finish', val);
|
|
}
|
|
|
|
const clear = () => {
|
|
captchaValue.value = '';
|
|
emit('update:modelValue', '');
|
|
}
|
|
|
|
defineExpose({ clear })
|
|
|
|
// 发送验证码
|
|
const sendCode = () => {
|
|
emit('sendCode');
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.captcha-container {
|
|
:deep(.el-form-item__content) {
|
|
flex-wrap: nowrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
:deep(.el-input-otp) {
|
|
--el-input-otp-font-size: 18px;
|
|
--el-input-otp-width: 40px;
|
|
--el-input-otp-height: 40px;
|
|
}
|
|
}
|
|
|
|
.form-btn {
|
|
height: 40px;
|
|
}
|
|
</style> |