Skip to content

Commit 801d346

Browse files
committed
FaModal 组件增加 beforeClose 回调函数,优化关闭逻辑并支持异步处理
1 parent 0a94076 commit 801d346

File tree

3 files changed

+119
-22
lines changed

3 files changed

+119
-22
lines changed

src/ui/components/FaModal/index.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export interface ModalProps {
2222
cancelButtonText?: string
2323
confirmButtonDisabled?: boolean
2424
confirmButtonLoading?: boolean
25+
beforeClose?: (
26+
action: 'confirm' | 'cancel' | 'close',
27+
done: () => void
28+
) => void
2529
header?: boolean
2630
footer?: boolean
2731
closeOnClickOverlay?: boolean
@@ -30,7 +34,6 @@ export interface ModalProps {
3034
headerClass?: HTMLAttributes['class']
3135
contentClass?: HTMLAttributes['class']
3236
footerClass?: HTMLAttributes['class']
33-
modalId?: string
3437
}
3538
export interface ModalEmits {
3639
'update:modelValue': [value: boolean]
@@ -44,13 +47,13 @@ export interface ModalEmits {
4447

4548
type alertOptions = Pick<ModalProps, 'title' | 'description' | 'icon' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
4649
content: string
47-
onConfirm?: () => any
50+
onConfirm?: () => void
4851
}
4952

50-
type confirmOptions = Pick<ModalProps, 'title' | 'description' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'cancelButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
53+
type confirmOptions = Pick<ModalProps, 'title' | 'description' | 'alignCenter' | 'overlay' | 'overlayBlur' | 'confirmButtonText' | 'cancelButtonText' | 'confirmButtonDisabled' | 'confirmButtonLoading' | 'beforeClose' | 'closeOnClickOverlay' | 'closeOnPressEscape' | 'class' | 'headerClass' | 'contentClass' | 'footerClass'> & {
5154
content: string
52-
onConfirm?: () => any
53-
onCancel?: () => any
55+
onConfirm?: () => void
56+
onCancel?: () => void
5457
}
5558

5659
export function useFaModal() {
@@ -67,7 +70,6 @@ export function useFaModal() {
6770
closeOnClickOverlay: false,
6871
contentClass: 'py-0 min-h-auto',
6972
footerClass: 'p-4',
70-
modalId: useId(),
7173
onClosed: () => {
7274
app.unmount()
7375
},
@@ -89,7 +91,6 @@ export function useFaModal() {
8991
closeOnClickOverlay: false,
9092
contentClass: 'py-0 min-h-auto',
9193
footerClass: 'p-4',
92-
modalId: useId(),
9394
onClosed: () => {
9495
app.unmount()
9596
},
@@ -111,7 +112,6 @@ export function useFaModal() {
111112
closeOnClickOverlay: false,
112113
contentClass: 'py-0 min-h-auto',
113114
footerClass: 'p-4',
114-
modalId: useId(),
115115
onClosed: () => {
116116
app.unmount()
117117
},
@@ -133,7 +133,6 @@ export function useFaModal() {
133133
closeOnClickOverlay: false,
134134
contentClass: 'py-0 min-h-auto',
135135
footerClass: 'p-4',
136-
modalId: useId(),
137136
onClosed: () => {
138137
app.unmount()
139138
},
@@ -155,7 +154,6 @@ export function useFaModal() {
155154
contentClass: 'py-0 min-h-auto',
156155
footerClass: 'p-4',
157156
showCancelButton: true,
158-
modalId: useId(),
159157
onClosed: () => {
160158
app.unmount()
161159
},

src/ui/components/FaModal/index.vue

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,35 +83,77 @@ function setTransform() {
8383
}
8484
8585
watch(isOpen, (val) => {
86+
emits('update:modelValue', val)
8687
if (val) {
8788
nextTick(() => {
8889
if (dialogContentRef.value) {
8990
dialogRef.value = dialogContentRef.value.el?.$el
9091
setTransform()
9192
}
9293
})
94+
emits('open')
95+
}
96+
else {
97+
emits('close')
9398
}
9499
})
95100
96-
function updateOpen(value: boolean) {
97-
isOpen.value = value
98-
emits('update:modelValue', value)
101+
async function updateOpen(value: boolean) {
99102
if (value) {
103+
isOpen.value = value
100104
emits('open')
101105
}
102106
else {
103-
emits('close')
107+
if (props.beforeClose) {
108+
await props.beforeClose(
109+
'close',
110+
() => {
111+
isOpen.value = value
112+
emits('close')
113+
},
114+
)
115+
}
116+
else {
117+
isOpen.value = value
118+
emits('close')
119+
}
104120
}
105121
}
106122
107-
function onConfirm() {
108-
updateOpen(false)
109-
emits('confirm')
123+
const isConfirmButtonLoading = ref(false)
124+
125+
async function onConfirm() {
126+
if (props.beforeClose) {
127+
isConfirmButtonLoading.value = true
128+
await props.beforeClose(
129+
'confirm',
130+
() => {
131+
isOpen.value = false
132+
emits('confirm')
133+
},
134+
)
135+
isConfirmButtonLoading.value = false
136+
}
137+
else {
138+
isOpen.value = false
139+
emits('confirm')
140+
}
110141
}
111142
112-
function onCancel() {
113-
updateOpen(false)
114-
emits('cancel')
143+
async function onCancel() {
144+
if (props.beforeClose) {
145+
await props.beforeClose(
146+
'cancel',
147+
() => {
148+
isOpen.value = false
149+
emits('cancel')
150+
},
151+
)
152+
}
153+
else {
154+
isOpen.value = false
155+
emits('cancel')
156+
}
115157
}
116158
117159
function handleFocusOutside(e: Event) {
@@ -223,7 +265,7 @@ function handleAnimationEnd() {
223265
<FaButton v-if="showCancelButton" variant="outline" @click="onCancel">
224266
{{ cancelButtonText }}
225267
</FaButton>
226-
<FaButton v-if="showConfirmButton" :disabled="confirmButtonDisabled" :loading="confirmButtonLoading" @click="onConfirm">
268+
<FaButton v-if="showConfirmButton" :disabled="confirmButtonDisabled" :loading="confirmButtonLoading || isConfirmButtonLoading" @click="onConfirm">
227269
{{ confirmButtonText }}
228270
</FaButton>
229271
</slot>

src/views/component_built_in_example/modal.vue

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ meta:
44
</route>
55

66
<script setup lang="ts">
7+
import { toast } from 'vue-sonner'
78
import { useFaModal } from '@/ui/components/FaModal'
89
910
const modal = ref(false)
@@ -25,34 +26,87 @@ watch(() => modalInfo.value.loading, (loading) => {
2526
}
2627
})
2728
29+
function handleBeforeClose(action: 'confirm' | 'cancel' | 'close', done: () => void) {
30+
if (action === 'close') {
31+
useFaModal().confirm({
32+
title: '提示',
33+
content: '确定要关闭吗?',
34+
onConfirm: () => {
35+
done()
36+
},
37+
})
38+
}
39+
else {
40+
done()
41+
}
42+
}
43+
2844
function showModalInfo() {
2945
useFaModal().info({
3046
title: '温馨提醒',
3147
content: '这是 info 弹窗',
48+
onConfirm: () => {
49+
toast.info('你点了确定')
50+
},
3251
})
3352
}
3453
function showModalSuccess() {
3554
useFaModal().success({
3655
title: '温馨提醒',
3756
content: '这是 success 弹窗',
57+
onConfirm: () => {
58+
toast.success('你点了确定')
59+
},
3860
})
3961
}
4062
function showModalWarning() {
4163
useFaModal().warning({
4264
title: '温馨提醒',
4365
content: '这是 warning 弹窗',
66+
onConfirm: () => {
67+
toast.warning('你点了确定')
68+
},
4469
})
4570
}
4671
function showModalError() {
4772
useFaModal().error({
4873
title: '温馨提醒',
4974
content: '这是 confirm 弹窗',
75+
onConfirm: () => {
76+
toast.error('你点了确定')
77+
},
5078
})
5179
}
5280
function showModalConfirm() {
5381
useFaModal().confirm({
5482
title: '温馨提醒',
5583
content: '这是 confirm 弹窗',
84+
onConfirm: () => {
85+
toast.success('你点了确定')
86+
},
87+
})
88+
}
89+
90+
function showModalPromiseConfirm() {
91+
useFaModal().confirm({
92+
title: '温馨提醒',
93+
content: '这是 confirm 弹窗',
94+
confirmButtonText: '确认(随机成功或失败)',
95+
beforeClose: async (action, done) => {
96+
if (action === 'confirm') {
97+
await new Promise(resolve => setTimeout(resolve, 1000))
98+
if (Math.random() > 0.5) {
99+
toast.success('成功了!')
100+
done()
101+
}
102+
else {
103+
toast.error('失败了!')
104+
}
105+
}
106+
else {
107+
done()
108+
}
109+
},
56110
})
57111
}
58112
</script>
@@ -80,8 +134,11 @@ function showModalConfirm() {
80134
<FaButton @click="showModalConfirm">
81135
Confirm
82136
</FaButton>
137+
<FaButton @click="showModalPromiseConfirm">
138+
Confirm with promise
139+
</FaButton>
83140
</div>
84-
<FaModal v-model="modal" title="标题" description="这里是一段描述介绍" :maximizable="modalInfo.maximizable" :closable="modalInfo.closable" :draggable="modalInfo.draggable" :center="modalInfo.center" :loading="modalInfo.loading" :header="modalInfo.header" :footer="modalInfo.footer">
141+
<FaModal v-model="modal" title="标题" description="这里是一段描述介绍" :maximizable="modalInfo.maximizable" :closable="modalInfo.closable" :draggable="modalInfo.draggable" :center="modalInfo.center" :loading="modalInfo.loading" :header="modalInfo.header" :footer="modalInfo.footer" :before-close="handleBeforeClose">
85142
<div :class="modalInfo.contentHeight">
86143
<div class="flex-start-center flex-wrap gap-2">
87144
<FaButton :variant="modalInfo.maximizable ? 'default' : 'outline'" class="w-full" @click="modalInfo.maximizable = !modalInfo.maximizable">

0 commit comments

Comments
 (0)