vue3 - 自定义弹框组件

vue3 - 自定义弹框组件_第1张图片

写了一个弹框组件
<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-input
              v-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 | number
  code: 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 = true
      const interval = setInterval(() => {
        if (myState.time-- <= 0) {
          myState.time = 60
          myState.smsSendFlag = false
          clearInterval(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>

你可能感兴趣的:(vue.js)