vue3.0全局打开弹窗hooks函数封装

292 阅读1分钟

思路

useDialog函数:
1、创建一个div节点,将它插入到body节点下
2、再创建一个mounted()函数,里面包含一个vnode,当调用mouted函数进行挂载时,通过render函数将该vnode渲染到刚刚创建的div节点下。
3、再创建一个unmount()函数,渲染为null,关闭弹出的时候卸载,这样我们就不需要在每个组件引入dialog并且每个dialog要声明一个变量控制它是否显示了。

引用

useDialog.ts

import { useDialog } from '@/hooks/dialog'
const useDialogs = useDialog()
// 打开账单弹框
useDialogs.mounted({
    component: XXX(弹窗插槽组件),
    dialogProps: {
      title: '标题',
      width: '960px'
    },
    childrenProps: {
      note: '一些自定义传值字段',
      onRemoves: () => {
        useDialogs.unmount()
      },
      onHandleConfirm: async () => {
        loading.value = true
        useDialogs.unmount()
      }
    }
})

hooks函数封装 - 完整代码

dialog.ts

import { ElDialog } from 'element-plus'
import { getCurrentInstance, h, render, VNode } from 'vue'

export function useDialog() {
  const div = document.createElement('div')
  document.body.appendChild(div)
  const current = getCurrentInstance()
  
  function mounted(opt: any) {
    const vnode = h(
      ElDialog,
      {
        modelValue: true,
        title: '默认弹框',
        closOnClickModal: false,
        ...opt.dialogProps,
        customClass: `app-custom_dialog ${opt.dialogProps.customClass || ''}`,
        onRemove: () => unmount(),
        'onUpdate:modelValue': (v: boolean) => {
          if (!v) {
            unmount()
          }
        }
      },
      {
        // ElDialog 默认插槽
        default: () =>
          h(opt.component, {
            ...opt.childrenProps,
            onRemove: () => {
              unmount()
            }
          }),
        ...opt.childrenSlot
      }
    )
    vnode.appContext = current?.appContext!
    render(vnode, div)
    return unmount
  }
  
  function unmount() {
    render(null, div)
  }
  
  return {
    mounted,
    unmount
  }
}