vue3实现命令式弹窗

效果图

在这里插入图片描述

代码区域

首先实现弹窗组件my-modal.vue

这里实现一个极简易弹窗作为示例,其他功能和样式可自行补充和优化;

<template>
  <div class="modal-mask">
    <div class="modal-wrap">
      <div class="modal">
        <div class="modal-header">{{ title }}</div>
        <div class="modal-body">
          <component
            v-if="isVNode(typeof content === 'function' ? content() : content)"
            :is="content"
          ></component>
          <span v-else>{{ content }}</span>
        </div>
        <div class="modal-footer">
          <button @click="emits('cancel')">取消</button>
          <button @click="emits('confirm')" style="margin-left: 12px">
            确定
          </button>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { isVNode } from "vue";
const props = defineProps({
  open: {
    type: Boolean,
    default: false,
  },
  title: {
    type: String,
    default: "弹窗标题",
  },
  content: {
    type: [Function, Object, String],
    default: "弹窗内容",
  },
});
const emits = defineEmits(["confirm", "cancel"]);
</script>

<style lang="scss">
.modal-mask {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.38);
  z-index: 1000;
  > .modal-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    > .modal {
      width: 500px;
      height: 300px;
      background-color: #ffffff;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      > .modal-header {
        display: flex;
        align-items: center;
        padding: 10px 12px;
        border-bottom: 1px solid #e8e8e8;
      }
      > .modal-body {
        padding: 24px;
      }
      > .modal-footer {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        padding: 10px 12px;
        border-top: 1px solid #e8e8e8;
      }
    }
  }
}
</style>

my-modal.js文件

import { h, render } from 'vue'
import MyDialog from './my-modal.vue'

export default function (option) {
    const divDom = document.createElement('div')
    document.body.appendChild(divDom);
    divDom.id = `modal-${Math.floor(Math.random() * 1000000)}`
    return new Promise((resolve, reject) => {

        // 关闭弹窗
        const closeModal = () => {
            render(null, divDom)
            document.body.removeChild(divDom)
        }

        // 确定
        const onConfirm = async () => {
            await option.onConfirm?.()
            closeModal()
            resolve()
        }

        // 取消
        const onCancel = async () => {
            await option.onCancel?.()
            closeModal()
            reject('关闭弹窗')
        }

        const vNode = h(MyDialog, {
            ...option,
            onConfirm,
            onCancel,
        })
        render(vNode, divDom)
    })
}

命令式使用该弹窗

<template>
  <div>
    <button @click="openModal">打开弹窗</button>
  </div>
</template>

<script lang="jsx" setup>
import MyModal from "@/components/my-modal.js";

const openModal = async () => {
  await MyModal({ title: "系统提示", content: () => <span style="color: red">确定删除该信息吗?</span>, onConfirm: () => {console.log('点击确定')}  });
  // 点击确定的后续操作
  console.log("弹窗点击确定后的业务逻辑");
};
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值