效果图
代码区域
首先实现弹窗组件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>