在 vue 中,使用 createSyncModal 同步打开弹窗

64 阅读1分钟

存在缺陷,代码修复中

代码实现

// modal-helper.ts

import type { Component } from 'vue';
import { h, render } from 'vue';

import { useAppStore } from '@/store/modules/app';

/**
 * 创建同步模态框
 * @param loader 模态框组件加载函数
 * @param props 传递给模态框的属性
 * @returns Promise<{success: boolean, data?: any}>
 */
export function createSyncModal(
  loader: () => Promise<{ default: Component }>,
  props: Record<string, any> = {},
) {
  return new Promise<{ success: boolean; data?: any }>((resolve) => {
    const container = document.createElement('div');
    document.body.appendChild(container);

    /** 移除模态框 */
    const cleanup = () => {
      render(null, container);
      container.remove();
    };

    loader().then(({ default: ModalComponent }) => {
      // 取消时返回 {success: false}
      const handleClose = () => {
        cleanup();
        resolve({ success: false });
      };

      // 确认时返回 {success: true, data: result}
      const handleOk = (result: any) => {
        cleanup();
        resolve({ success: true, data: result });
      };

      // 合并props和事件处理
      // 这里只保留了 ok、cancel、update:visible 事件
      const mergedProps = {
        ...props,
        visible: true,
        onOk: async (...args: any[]) => {
          handleOk(args);
        },
        onCancel: async () => {
          handleClose();
        },
        'onUpdate:visible': (val: boolean) => {
          props['onUpdate:visible']?.(val);
          if (!val) {
            handleClose();
          }
        },
      };

      const vnode = h(ModalComponent, mergedProps);
      const appStore = useAppStore();
      const app = appStore.getApp; // !!!需要在 createApp 处,保存起来 app 实例

      // 使用同一个 vue 实例
      if (app) {
        vnode.appContext = app._context;
      }

      render(vnode, container);
    });
  });
}

使用

import { createSyncModal } form 'xx/modal-helper'


const fn = async () => {
    /** 一些业务逻辑 */
    
    const { success, data } = await createSyncModal('@/xxx/xx-modal.vue', { /* props */ });
    
    if (!success) return;
    
    /** 一些业务逻辑 */
}