ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

vue3 - 自定义弹框组件

2026/9/9 14:23:27 拓冰建站 浏览量
vue3 - 自定义弹框组件

在这里插入图片描述

写了一个弹框组件
<template><transition name="modal-fade"><div v-if="showFlag" class="myModal"><div class="content"><div class="topBox"><div class="leftTitle"><span>{{ title }}</span></div><div class="rightClose" @click="cancelModal"><CloseOutlined /></div></div><slot name="content"></slot></div></div></transition>
</template><script setup lang="ts">
import { ref, toRefs } from 'vue'const props = defineProps({title: {type: String,default: '',},
})const { title } = toRefs(props)// 是否开启弹框
let showFlag = ref(false)// 开启
const showModal = () => {showFlag.value = true
}// 关闭
const cancelModal = () => {showFlag.value = false
}defineExpose({showModal,cancelModal,
})
</script><style lang="less" scoped>
// 这个动画是,打开弹框时,有一个缓慢打开的效果
@keyframes fadeIn {from {opacity: 0;}to {opacity: 1;}
}// 打开弹框时给它一个上下抖动的效果
@keyframes shake {0% { transform: translateY(0); }25% { transform: translateY(-10px); }50% { transform: translateY(0); }75% { transform: translateY(10px); }100% { transform: translateY(0); }
}.myModal {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.4);z-index: 100;animation: fadeIn 0.5s;// animation: fadeIn 0.5s, shake 0.5s;.content {position: absolute;left: 50%;top: 30%;transform: translate(-50%, -50%);background: #ffffff;width: 500px;padding: 10px;.topBox {display: flex;height: 30px;border-bottom: 1px solid #f0f0f0;padding: 0 10px 0 0;margin-bottom: 20px;cursor: pointer;.leftTitle {flex: 1;text-align: left;color: rgba(0, 0, 0, 0.8);font-weight: 600;font-size: 16px;}.rightClose {flex: 1;text-align: right;}}}
}// start - 效果为:关闭时,有一个缓慢消失的效果
.modal-fade-enter-active, .modal-fade-leave-active {transition: opacity 0.5s;
}
.modal-fade-enter, .modal-fade-leave-to {opacity: 0;
}
// end - 效果为:关闭时,有一个缓慢消失的效果
</style>
使用它
<template><MyModal ref="myModal" :title="title"><template #content><div style="display: grid; place-items: center"><a-form ref="loginForm" :model="formState" :label-col="labelCol" style="width: 360px"><a-form-item has-feedback name="userName"><a-input v-model:value="formState.phone" placeholder="请输入手机号" autocomplete="off"><template #prefix><UserOutlined style="color: rgba(0, 0, 0, 0.25)" /></template></a-input></a-form-item><a-form-item has-feedback name="code"><a-inputv-model:value="formState.code"placeholder="验证码"autocomplete="off"style="width: 240px"><template #prefix><MailOutlined style="color: rgba(0, 0, 0, 0.25)" /></template></a-input><a-button:disabled="myState.smsSendFlag"v-text="(!myState.smsSendFlag && '获取验证码') || `${myState.time} s`"@click="getSms"style="margin-left: 15px"type="primary"></a-button></a-form-item><a-form-item style="text-align: center"><a-button style="width: 360px" type="primary" block @click="handleSubmit">登录</a-button></a-form-item></a-form></div></template></MyModal>
</template><script setup lang="ts">
import { ref } from 'vue'import * as accountApi from '@/api/account'import MyModal from '@/components/MyModal/MyModal.vue'
import { message } from 'ant-design-vue'const myModal = ref()const showModal = () => {myModal.value?.showModal()
}defineExpose({showModal,
})let title = ref('x管家登陆')const myState = reactive({smsSendFlag: false,time: 60,
})let labelCol = { span: 4 }
interface formState {phone: string | numbercode: string | number
}
const formState = ref<formState>({phone: '',code: '',
})// 获取验证码
const getSms = async () => {let params = {phone: formState.value.phone,}if (params['phone'] == '') {message.error(`手机号不能为空~`)return}const hide = message.loading('验证码发送中..', 0)try {let { state, message: msg } = await accountApi.idleSendSms(params)if (state === 200) {myState.smsSendFlag = trueconst interval = setInterval(() => {if (myState.time-- <= 0) {myState.time = 60myState.smsSendFlag = falseclearInterval(interval)}}, 1000)} else {message.error(msg)}} catch (error) {message.error('网络请求连接失败~')}setTimeout(hide, 1)
}// 登录
const handleSubmit = async () => {let params = {phone: formState.value.phone,code: formState.value.code,}try {const { state, message: msg, token } = await accountApi.idleLogin(params)if (state === 200) {message.success('登录成功~')myModal.value?.cancelModal()} else {message.error(msg)}} catch (error) {message.error('网络请求发送失败~')}
}
</script>