feat: add opened and closed events for dialog (#4775)
parent
353e8be289
commit
06ba7cb224
|
@ -110,12 +110,14 @@ const [Modal, modalApi] = useVbenModal({
|
|||
|
||||
以下事件,只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。
|
||||
|
||||
| 事件名 | 描述 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` |
|
||||
| onCancel | 点击取消按钮触发 | `()=>void` |
|
||||
| onConfirm | 点击确认按钮触发 | `()=>void` |
|
||||
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` |
|
||||
| 事件名 | 描述 | 类型 | 版本号 |
|
||||
| --- | --- | --- | --- |
|
||||
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` | |
|
||||
| onCancel | 点击取消按钮触发 | `()=>void` | |
|
||||
| onClosed | 关闭动画播放完毕时触发 | `()=>void` | >5.4.3 |
|
||||
| onConfirm | 点击确认按钮触发 | `()=>void` | |
|
||||
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` | |
|
||||
| onOpened | 打开动画播放完毕时触发 | `()=>void` | >5.4.3 |
|
||||
|
||||
### Slots
|
||||
|
||||
|
|
|
@ -110,4 +110,19 @@ describe('modalApi', () => {
|
|||
expect(modalApi.store.state.title).toBe('Batch Title');
|
||||
expect(modalApi.store.state.confirmText).toBe('Batch Confirm');
|
||||
});
|
||||
|
||||
it('should call onClosed callback when provided', () => {
|
||||
const onClosed = vi.fn();
|
||||
const modalApiWithHook = new ModalApi({ onClosed });
|
||||
modalApiWithHook.onClosed();
|
||||
expect(onClosed).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call onOpened callback when provided', () => {
|
||||
const onOpened = vi.fn();
|
||||
const modalApiWithHook = new ModalApi({ onOpened });
|
||||
modalApiWithHook.open();
|
||||
modalApiWithHook.onOpened();
|
||||
expect(onOpened).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,12 @@ import { bindMethods, isFunction } from '@vben-core/shared/utils';
|
|||
export class ModalApi {
|
||||
private api: Pick<
|
||||
ModalApiOptions,
|
||||
'onBeforeClose' | 'onCancel' | 'onConfirm' | 'onOpenChange'
|
||||
| 'onBeforeClose'
|
||||
| 'onCancel'
|
||||
| 'onClosed'
|
||||
| 'onConfirm'
|
||||
| 'onOpenChange'
|
||||
| 'onOpened'
|
||||
>;
|
||||
// private prevState!: ModalState;
|
||||
private state!: ModalState;
|
||||
|
@ -23,8 +28,10 @@ export class ModalApi {
|
|||
connectedComponent: _,
|
||||
onBeforeClose,
|
||||
onCancel,
|
||||
onClosed,
|
||||
onConfirm,
|
||||
onOpenChange,
|
||||
onOpened,
|
||||
...storeState
|
||||
} = options;
|
||||
|
||||
|
@ -77,8 +84,10 @@ export class ModalApi {
|
|||
this.api = {
|
||||
onBeforeClose,
|
||||
onCancel,
|
||||
onClosed,
|
||||
onConfirm,
|
||||
onOpenChange,
|
||||
onOpened,
|
||||
};
|
||||
bindMethods(this);
|
||||
}
|
||||
|
@ -115,6 +124,15 @@ export class ModalApi {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗关闭动画播放完毕后的回调
|
||||
*/
|
||||
onClosed() {
|
||||
if (!this.state.isOpen) {
|
||||
this.api.onClosed?.();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认操作
|
||||
*/
|
||||
|
@ -122,6 +140,15 @@ export class ModalApi {
|
|||
this.api.onConfirm?.();
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗打开动画播放完毕后的回调
|
||||
*/
|
||||
onOpened() {
|
||||
if (this.state.isOpen) {
|
||||
this.api.onOpened?.();
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
this.store.setState((prev) => ({ ...prev, isOpen: true }));
|
||||
}
|
||||
|
|
|
@ -139,6 +139,11 @@ export interface ModalApiOptions extends ModalState {
|
|||
* 点击取消按钮的回调
|
||||
*/
|
||||
onCancel?: () => void;
|
||||
/**
|
||||
* 弹窗关闭动画结束的回调
|
||||
* @returns
|
||||
*/
|
||||
onClosed?: () => void;
|
||||
/**
|
||||
* 点击确定按钮的回调
|
||||
*/
|
||||
|
@ -149,4 +154,9 @@ export interface ModalApiOptions extends ModalState {
|
|||
* @returns
|
||||
*/
|
||||
onOpenChange?: (isOpen: boolean) => void;
|
||||
/**
|
||||
* 弹窗打开动画结束的回调
|
||||
* @returns
|
||||
*/
|
||||
onOpened?: () => void;
|
||||
}
|
||||
|
|
|
@ -188,10 +188,12 @@ function handleFocusOutside(e: Event) {
|
|||
:show-close="closable"
|
||||
close-class="top-3"
|
||||
@close-auto-focus="handleFocusOutside"
|
||||
@closed="() => modalApi?.onClosed()"
|
||||
@escape-key-down="escapeKeyDown"
|
||||
@focus-outside="handleFocusOutside"
|
||||
@interact-outside="interactOutside"
|
||||
@open-auto-focus="handerOpenAutoFocus"
|
||||
@opened="() => modalApi?.onOpened()"
|
||||
@pointer-down-outside="pointerDownOutside"
|
||||
>
|
||||
<DialogHeader
|
||||
|
|
|
@ -27,7 +27,9 @@ const props = withDefaults(
|
|||
>(),
|
||||
{ showClose: true },
|
||||
);
|
||||
const emits = defineEmits<{ close: [] } & DialogContentEmits>();
|
||||
const emits = defineEmits<
|
||||
{ close: []; closed: []; opened: [] } & DialogContentEmits
|
||||
>();
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const {
|
||||
|
@ -44,7 +46,13 @@ const delegatedProps = computed(() => {
|
|||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
|
||||
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
||||
|
||||
function onAnimationEnd() {
|
||||
if (props.open) {
|
||||
emits('opened');
|
||||
} else {
|
||||
emits('closed');
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
getContentRef: () => contentRef.value,
|
||||
});
|
||||
|
@ -57,6 +65,7 @@ defineExpose({
|
|||
</Transition>
|
||||
<DialogContent
|
||||
ref="contentRef"
|
||||
@animationend="onAnimationEnd"
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn(
|
||||
|
|
|
@ -7,10 +7,16 @@ const [Modal, modalApi] = useVbenModal({
|
|||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onClosed() {
|
||||
message.info('onClosed:关闭动画结束');
|
||||
},
|
||||
onConfirm() {
|
||||
message.info('onConfirm');
|
||||
// modalApi.close();
|
||||
},
|
||||
onOpened() {
|
||||
message.info('onOpened:打开动画结束');
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
|
|
Loading…
Reference in New Issue