feat: FaModal 组件增加 beforeClose 回调函数,优化关闭逻辑并支持异步处理

This commit is contained in:
Hooray
2025-06-10 14:37:25 +08:00
parent 3859c26f42
commit 6febfea146
2 changed files with 64 additions and 24 deletions
+8 -10
View File
@@ -22,6 +22,10 @@ export interface ModalProps {
cancelButtonText?: string
confirmButtonDisabled?: boolean
confirmButtonLoading?: boolean
beforeClose?: (
action: 'confirm' | 'cancel' | 'close',
done: () => void
) => void
header?: boolean
footer?: boolean
closeOnClickOverlay?: boolean
@@ -30,7 +34,6 @@ export interface ModalProps {
headerClass?: HTMLAttributes['class']
contentClass?: HTMLAttributes['class']
footerClass?: HTMLAttributes['class']
modalId?: string
}
export interface ModalEmits {
'update:modelValue': [value: boolean]
@@ -44,13 +47,13 @@ export interface ModalEmits {
type alertOptions = Pick<ModalProps, 'title' | 'description' | 'icon' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
content: string
onConfirm?: () => any
onConfirm?: () => void
}
type confirmOptions = Pick<ModalProps, 'title' | 'description' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'cancelButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
type confirmOptions = Pick<ModalProps, 'title' | 'description' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'cancelButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'beforeClose' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
content: string
onConfirm?: () => any
onCancel?: () => any
onConfirm?: () => void
onCancel?: () => void
}
export function useFaModal() {
@@ -67,7 +70,6 @@ export function useFaModal() {
closeOnClickOverlay: false,
contentClass: 'py-0 min-h-auto',
footerClass: 'p-4',
modalId: useId(),
onClosed: () => {
app.unmount()
},
@@ -89,7 +91,6 @@ export function useFaModal() {
closeOnClickOverlay: false,
contentClass: 'py-0 min-h-auto',
footerClass: 'p-4',
modalId: useId(),
onClosed: () => {
app.unmount()
},
@@ -111,7 +112,6 @@ export function useFaModal() {
closeOnClickOverlay: false,
contentClass: 'py-0 min-h-auto',
footerClass: 'p-4',
modalId: useId(),
onClosed: () => {
app.unmount()
},
@@ -133,7 +133,6 @@ export function useFaModal() {
closeOnClickOverlay: false,
contentClass: 'py-0 min-h-auto',
footerClass: 'p-4',
modalId: useId(),
onClosed: () => {
app.unmount()
},
@@ -155,7 +154,6 @@ export function useFaModal() {
contentClass: 'py-0 min-h-auto',
footerClass: 'p-4',
showCancelButton: true,
modalId: useId(),
onClosed: () => {
app.unmount()
},
+56 -14
View File
@@ -83,6 +83,7 @@ function setTransform() {
}
watch(isOpen, (val) => {
emits('update:modelValue', val)
if (val) {
nextTick(() => {
if (dialogContentRef.value) {
@@ -90,28 +91,69 @@ watch(isOpen, (val) => {
setTransform()
}
})
}
})
function updateOpen(value: boolean) {
isOpen.value = value
emits('update:modelValue', value)
if (value) {
emits('open')
}
else {
emits('close')
}
})
async function updateOpen(value: boolean) {
if (value) {
isOpen.value = value
emits('open')
}
else {
if (props.beforeClose) {
await props.beforeClose(
'close',
() => {
isOpen.value = value
emits('close')
},
)
}
else {
isOpen.value = value
emits('close')
}
}
}
function onConfirm() {
updateOpen(false)
emits('confirm')
const isConfirmButtonLoading = ref(false)
async function onConfirm() {
if (props.beforeClose) {
isConfirmButtonLoading.value = true
await props.beforeClose(
'confirm',
() => {
isOpen.value = false
emits('confirm')
},
)
isConfirmButtonLoading.value = false
}
else {
isOpen.value = false
emits('confirm')
}
}
function onCancel() {
updateOpen(false)
emits('cancel')
async function onCancel() {
if (props.beforeClose) {
await props.beforeClose(
'cancel',
() => {
isOpen.value = false
emits('cancel')
},
)
}
else {
isOpen.value = false
emits('cancel')
}
}
function handleFocusOutside(e: Event) {
@@ -223,7 +265,7 @@ function handleAnimationEnd() {
<FaButton v-if="showCancelButton" variant="outline" @click="onCancel">
{{ cancelButtonText }}
</FaButton>
<FaButton v-if="showConfirmButton" :disabled="confirmButtonDisabled" :loading="confirmButtonLoading" @click="onConfirm">
<FaButton v-if="showConfirmButton" :disabled="confirmButtonDisabled" :loading="confirmButtonLoading || isConfirmButtonLoading" @click="onConfirm">
{{ confirmButtonText }}
</FaButton>
</slot>