vue3实现命令式弹窗

效果图

vue3实现命令式弹窗_第1张图片

代码区域

首先实现弹窗组件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>

你可能感兴趣的:(vue3,vue)