import { ref, defineAsyncComponent, getCurrentInstance, computed, h, createApp, unref, provide, reactive } from 'vue' import type { Component, App, VNode, ComputedRef } from 'vue' import type { ElDialog } from 'element-plus' import Dialog from '@/components/Dialog/index.vue' import { DialogProps, DialogModalProps } from './props' const defaultModalProps: Omit = { title:'', showOk: true, showClose: false, hideCancel: false, okText: '确定', cancelText: '取消', footer: true, header: true, width: '60%' } /** * 获取组件实例的 provides * @param instance Vue 组件实例 * @returns 组件实例及其父级的 provides 对象 */ function getProvides(instance: any): Record { let provides = instance?.provides || {} if (instance.parent) { provides = { ...provides, ...getProvides(instance.parent) } } return provides } const useDialog = (initialOptions: DialogProps) => { const modalRef = ref | null>(null) const currentInstance = getCurrentInstance() as any const provides = getProvides(currentInstance) // 用于保存对话框应用实例和可见性状态 let dialogApp: App | null = null const visible = ref(false) let container: HTMLElement | null = null // 使用reactive存储options,以便能够响应式更新 const options = reactive({ ...initialOptions }) const mergeModalOptions: ComputedRef = computed(() => { return { ...defaultModalProps, ...options.modalProps } }) const openModal = () => { // 判断content类型 const isAsync = typeof options.content === 'function' const isString = typeof options.content === 'string' const modalComponent = isAsync ? defineAsyncComponent(options.content as () => Promise) : isString ? h('div', options.content as string) : options.content container = document.createElement('div') document.body.appendChild(container) // 状态管理 visible.value = true dialogApp = createApp({ setup() { const closed = () => { if (dialogApp) { dialogApp.unmount() dialogApp = null } if (container) { container.remove() container = null } } const instance = getCurrentInstance() as any if (instance) { instance.provides = { ...instance.provides, ...provides } // 使用provide提供上下文 provide('parentInstance', currentInstance) provide('dialogInstance', instance) provide('dialogProvides', provides) } const onOk = async () => { // 调用props中传递的onOk回调函数 try { await unref(options.modalProps)?.onOk?.(); // 如果需要,可以在这里添加默认的关闭行为 } catch (error) { console.error('Dialog onOk error:', error); } } return () => { return h( Dialog, { ...unref(mergeModalOptions), modelValue: visible.value, 'onUpdate:modelValue': (val: boolean) => { visible.value = val }, onOk: onOk, onClosed: () => { //如果需要回调就调用回调 unref(options.contentProps)?.onClosed?.() closed() } }, () => h(modalComponent, { ...options.contentProps, // 将当前实例上下文传递给子组件 instance: instance, // 传递provides provides: provides, // 如果需要,还可以传递其他上下文信息 parentContext: currentInstance }) ) } } }) // 挂载应用 dialogApp.mount(container) } const closeModal = () => { // 设置可见性为false,触发对话框关闭 if (unref(visible)) { visible.value = false } // 如果dialogApp存在,手动卸载 if (dialogApp) { setTimeout(() => { dialogApp?.unmount() dialogApp = null if (container) { container.remove() container = null } }, 300) // 给动画效果一些时间 } } //更新属性 const updateModalProps = (props: Partial) => { if (!dialogApp) { return false } // 更新modalProps if (props.modalProps) { options.modalProps = { ...options.modalProps, ...props.modalProps } } // 更新contentProps if (props.contentProps) { options.contentProps = { ...options.contentProps, ...props.contentProps } } // 如果提供了新的content,需要重新打开对话框 if (props.content) { options.content = props.content closeModal() setTimeout(() => { openModal() }, 300) } return true } return { modalRef: modalRef, openModal: openModal, closeModal: closeModal, updateModalProps: updateModalProps } } export default useDialog