159 lines
4.2 KiB
TypeScript
159 lines
4.2 KiB
TypeScript
import type { AppContext, VNode } from 'vue'
|
|
import { createVNode, getCurrentInstance, nextTick, render } from 'vue'
|
|
import Modal from './index'
|
|
|
|
function omit<T extends Record<string, any>, K extends keyof T>(
|
|
object: T,
|
|
keys: K[],
|
|
): Omit<T, K> {
|
|
const result = { ...object }
|
|
keys.forEach(key => delete result[key])
|
|
return result
|
|
}
|
|
|
|
export interface ModalOptions {
|
|
layout?: string | VNode | (() => VNode)
|
|
|
|
title?: string | VNode | (() => VNode)
|
|
content?: string | VNode | (() => VNode)
|
|
footer?: string | VNode | (() => VNode)
|
|
position?: 'top' | 'center' | 'bottom'
|
|
confirmBtnProps?: Record<string, any>
|
|
cancelBtnProps?: Record<string, any>
|
|
width?: string
|
|
height?: string
|
|
fullscreen?: boolean
|
|
showClose?: boolean
|
|
showFullscreen?: boolean
|
|
draggable?: boolean
|
|
draggableSelector?: string
|
|
confirmBtn?: any
|
|
cancelBtn?: any
|
|
mask?: boolean
|
|
maskClosable?: boolean
|
|
onConfirm?: () => void
|
|
onCancel?: () => void
|
|
onClose?: () => void
|
|
}
|
|
|
|
function createModal(options: ModalOptions & { type?: string }, appContext?: AppContext) {
|
|
let container: HTMLDivElement | null = document.createElement('div')
|
|
document.body.appendChild(container)
|
|
|
|
let vm: VNode
|
|
|
|
const handleConfirm = () => {
|
|
if (vm.component)
|
|
vm.component.props.visible = false
|
|
options.onConfirm?.()
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
if (vm.component)
|
|
vm.component.props.visible = false
|
|
options.onCancel?.()
|
|
}
|
|
|
|
const handleClose = async () => {
|
|
await nextTick()
|
|
if (container) {
|
|
render(null, container)
|
|
document.body.removeChild(container)
|
|
}
|
|
container = null
|
|
options.onClose?.()
|
|
}
|
|
|
|
const defaultConfig = {
|
|
visible: true,
|
|
onConfirm: handleConfirm,
|
|
onCancel: handleCancel,
|
|
onClose: handleClose,
|
|
type: options.type ?? 'default',
|
|
}
|
|
vm = createVNode(
|
|
Modal,
|
|
{
|
|
...defaultConfig,
|
|
...omit(options, ['layout', 'content', 'title', 'footer', 'onConfirm', 'onCancel', 'onClose']),
|
|
},
|
|
options.layout
|
|
? {
|
|
layout:
|
|
typeof options.layout === 'function'
|
|
? options.layout
|
|
: () => options.layout,
|
|
}
|
|
: {
|
|
default: options.content
|
|
? typeof options.content === 'function'
|
|
? options.content
|
|
: () => options.content
|
|
: undefined,
|
|
title: options.title
|
|
? typeof options.title === 'function'
|
|
? options.title
|
|
: () => options.title
|
|
: undefined,
|
|
footer: options.footer
|
|
? typeof options.footer === 'function'
|
|
? options.footer
|
|
: () => options.footer
|
|
: undefined,
|
|
},
|
|
)
|
|
|
|
// 自动获取 appContext,除非手动传入
|
|
const instanceAppContext = appContext ?? getCurrentInstance()?.appContext ?? undefined
|
|
if (instanceAppContext) {
|
|
vm.appContext = instanceAppContext
|
|
}
|
|
|
|
render(vm, container)
|
|
|
|
return {
|
|
close: () => {
|
|
if (vm.component)
|
|
vm.component.props.visible = false
|
|
},
|
|
update: (newOptions: Partial<ModalOptions>) => {
|
|
if (vm.component) {
|
|
Object.entries(newOptions).forEach(([key, val]) => {
|
|
vm.component!.props[key] = val
|
|
})
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
type ModalType = 'default' | 'info' | 'success' | 'warning' | 'danger' | 'question'
|
|
|
|
export function useModal() {
|
|
const open = (options: ModalOptions & { type?: ModalType }, appContext?: AppContext) =>
|
|
createModal({ ...options, type: options.type ?? 'default' }, appContext)
|
|
|
|
const info = (options: ModalOptions, appContext?: AppContext) =>
|
|
createModal({ ...options, type: 'info' }, appContext)
|
|
|
|
const success = (options: ModalOptions, appContext?: AppContext) =>
|
|
createModal({ ...options, type: 'success' }, appContext)
|
|
|
|
const warning = (options: ModalOptions, appContext?: AppContext) =>
|
|
createModal({ ...options, type: 'warning' }, appContext)
|
|
|
|
const danger = (options: ModalOptions, appContext?: AppContext) =>
|
|
createModal({ ...options, type: 'danger' }, appContext)
|
|
|
|
const question = (options: ModalOptions, appContext?: AppContext) =>
|
|
createModal({ ...options, type: 'question' }, appContext)
|
|
|
|
return {
|
|
open,
|
|
info,
|
|
success,
|
|
warning,
|
|
danger,
|
|
question,
|
|
}
|
|
}
|