123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- 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<DialogModalProps, 'content'> = {
- 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<string, any> {
- let provides = instance?.provides || {}
- if (instance.parent) {
- provides = { ...provides, ...getProvides(instance.parent) }
- }
- return provides
- }
- const useDialog = (initialOptions: DialogProps) => {
- const modalRef = ref<InstanceType<typeof ElDialog> | 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<DialogProps>({
- ...initialOptions
- })
- const mergeModalOptions: ComputedRef<DialogModalProps> = 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<Component>)
- : 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<DialogProps>) => {
- 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
|