Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
commit
a30029a33d
@ -110,12 +110,14 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
|
|
||||||
以下事件,只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。
|
以下事件,只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。
|
||||||
|
|
||||||
| 事件名 | 描述 | 类型 |
|
| 事件名 | 描述 | 类型 | 版本号 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` |
|
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` | |
|
||||||
| onCancel | 点击取消按钮触发 | `()=>void` |
|
| onCancel | 点击取消按钮触发 | `()=>void` | |
|
||||||
| onConfirm | 点击确认按钮触发 | `()=>void` |
|
| onClosed | 关闭动画播放完毕时触发 | `()=>void` | >5.4.3 |
|
||||||
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` |
|
| onConfirm | 点击确认按钮触发 | `()=>void` | |
|
||||||
|
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` | |
|
||||||
|
| onOpened | 打开动画播放完毕时触发 | `()=>void` | >5.4.3 |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@ const activePath = ref<MenuProvider['activePath']>(props.defaultActive);
|
|||||||
const items = ref<MenuProvider['items']>({});
|
const items = ref<MenuProvider['items']>({});
|
||||||
const subMenus = ref<MenuProvider['subMenus']>({});
|
const subMenus = ref<MenuProvider['subMenus']>({});
|
||||||
const mouseInChild = ref(false);
|
const mouseInChild = ref(false);
|
||||||
const defaultSlots: VNodeArrayChildren = slots.default?.() ?? [];
|
|
||||||
|
|
||||||
const isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {
|
const isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {
|
||||||
return (
|
return (
|
||||||
@ -73,6 +72,9 @@ const isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const getSlot = computed(() => {
|
const getSlot = computed(() => {
|
||||||
|
// 更新插槽内容
|
||||||
|
const defaultSlots: VNodeArrayChildren = slots.default?.() ?? [];
|
||||||
|
|
||||||
const originalSlot = flattedChildren(defaultSlots) as VNodeArrayChildren;
|
const originalSlot = flattedChildren(defaultSlots) as VNodeArrayChildren;
|
||||||
const slotDefault =
|
const slotDefault =
|
||||||
sliceIndex.value === -1
|
sliceIndex.value === -1
|
||||||
@ -718,6 +720,10 @@ $namespace: vben;
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: var(--menu-item-height);
|
height: var(--menu-item-height);
|
||||||
|
|
||||||
|
span {
|
||||||
|
@include menu-title;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-collapse-show-title {
|
&.is-collapse-show-title {
|
||||||
|
@ -42,7 +42,9 @@ const hasChildren = computed(() => {
|
|||||||
:icon="menu.icon"
|
:icon="menu.icon"
|
||||||
:path="menu.path"
|
:path="menu.path"
|
||||||
>
|
>
|
||||||
<template #title>{{ menu.name }}</template>
|
<template #title>
|
||||||
|
<span>{{ menu.name }}</span>
|
||||||
|
</template>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<SubMenuComp
|
<SubMenuComp
|
||||||
v-else
|
v-else
|
||||||
@ -59,7 +61,9 @@ const hasChildren = computed(() => {
|
|||||||
class="right-6"
|
class="right-6"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #title>{{ menu.name }}</template>
|
<template #title>
|
||||||
|
<span>{{ menu.name }}</span>
|
||||||
|
</template>
|
||||||
<template v-for="childItem in menu.children || []" :key="childItem.path">
|
<template v-for="childItem in menu.children || []" :key="childItem.path">
|
||||||
<SubMenu :menu="childItem" />
|
<SubMenu :menu="childItem" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -110,4 +110,19 @@ describe('modalApi', () => {
|
|||||||
expect(modalApi.store.state.title).toBe('Batch Title');
|
expect(modalApi.store.state.title).toBe('Batch Title');
|
||||||
expect(modalApi.store.state.confirmText).toBe('Batch Confirm');
|
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 {
|
export class ModalApi {
|
||||||
private api: Pick<
|
private api: Pick<
|
||||||
ModalApiOptions,
|
ModalApiOptions,
|
||||||
'onBeforeClose' | 'onCancel' | 'onConfirm' | 'onOpenChange'
|
| 'onBeforeClose'
|
||||||
|
| 'onCancel'
|
||||||
|
| 'onClosed'
|
||||||
|
| 'onConfirm'
|
||||||
|
| 'onOpenChange'
|
||||||
|
| 'onOpened'
|
||||||
>;
|
>;
|
||||||
// private prevState!: ModalState;
|
// private prevState!: ModalState;
|
||||||
private state!: ModalState;
|
private state!: ModalState;
|
||||||
@ -23,8 +28,10 @@ export class ModalApi {
|
|||||||
connectedComponent: _,
|
connectedComponent: _,
|
||||||
onBeforeClose,
|
onBeforeClose,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
onClosed,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
|
onOpened,
|
||||||
...storeState
|
...storeState
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
@ -77,8 +84,10 @@ export class ModalApi {
|
|||||||
this.api = {
|
this.api = {
|
||||||
onBeforeClose,
|
onBeforeClose,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
onClosed,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
|
onOpened,
|
||||||
};
|
};
|
||||||
bindMethods(this);
|
bindMethods(this);
|
||||||
}
|
}
|
||||||
@ -123,6 +132,15 @@ export class ModalApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹窗关闭动画播放完毕后的回调
|
||||||
|
*/
|
||||||
|
onClosed() {
|
||||||
|
if (!this.state.isOpen) {
|
||||||
|
this.api.onClosed?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确认操作
|
* 确认操作
|
||||||
*/
|
*/
|
||||||
@ -130,6 +148,15 @@ export class ModalApi {
|
|||||||
this.api.onConfirm?.();
|
this.api.onConfirm?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹窗打开动画播放完毕后的回调
|
||||||
|
*/
|
||||||
|
onOpened() {
|
||||||
|
if (this.state.isOpen) {
|
||||||
|
this.api.onOpened?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open() {
|
open() {
|
||||||
this.store.setState((prev) => ({ ...prev, isOpen: true }));
|
this.store.setState((prev) => ({ ...prev, isOpen: true }));
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,11 @@ export interface ModalApiOptions extends ModalState {
|
|||||||
* 点击取消按钮的回调
|
* 点击取消按钮的回调
|
||||||
*/
|
*/
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
|
/**
|
||||||
|
* 弹窗关闭动画结束的回调
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
onClosed?: () => void;
|
||||||
/**
|
/**
|
||||||
* 点击确定按钮的回调
|
* 点击确定按钮的回调
|
||||||
*/
|
*/
|
||||||
@ -149,4 +154,9 @@ export interface ModalApiOptions extends ModalState {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
onOpenChange?: (isOpen: boolean) => void;
|
onOpenChange?: (isOpen: boolean) => void;
|
||||||
|
/**
|
||||||
|
* 弹窗打开动画结束的回调
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
onOpened?: () => void;
|
||||||
}
|
}
|
||||||
|
@ -188,10 +188,12 @@ function handleFocusOutside(e: Event) {
|
|||||||
:show-close="closable"
|
:show-close="closable"
|
||||||
close-class="top-3"
|
close-class="top-3"
|
||||||
@close-auto-focus="handleFocusOutside"
|
@close-auto-focus="handleFocusOutside"
|
||||||
|
@closed="() => modalApi?.onClosed()"
|
||||||
@escape-key-down="escapeKeyDown"
|
@escape-key-down="escapeKeyDown"
|
||||||
@focus-outside="handleFocusOutside"
|
@focus-outside="handleFocusOutside"
|
||||||
@interact-outside="interactOutside"
|
@interact-outside="interactOutside"
|
||||||
@open-auto-focus="handerOpenAutoFocus"
|
@open-auto-focus="handerOpenAutoFocus"
|
||||||
|
@opened="() => modalApi?.onOpened()"
|
||||||
@pointer-down-outside="pointerDownOutside"
|
@pointer-down-outside="pointerDownOutside"
|
||||||
>
|
>
|
||||||
<DialogHeader
|
<DialogHeader
|
||||||
|
@ -27,7 +27,9 @@ const props = withDefaults(
|
|||||||
>(),
|
>(),
|
||||||
{ showClose: true },
|
{ showClose: true },
|
||||||
);
|
);
|
||||||
const emits = defineEmits<{ close: [] } & DialogContentEmits>();
|
const emits = defineEmits<
|
||||||
|
{ close: []; closed: []; opened: [] } & DialogContentEmits
|
||||||
|
>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
const {
|
const {
|
||||||
@ -44,7 +46,13 @@ const delegatedProps = computed(() => {
|
|||||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
|
|
||||||
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
||||||
|
function onAnimationEnd() {
|
||||||
|
if (props.open) {
|
||||||
|
emits('opened');
|
||||||
|
} else {
|
||||||
|
emits('closed');
|
||||||
|
}
|
||||||
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getContentRef: () => contentRef.value,
|
getContentRef: () => contentRef.value,
|
||||||
});
|
});
|
||||||
@ -57,6 +65,7 @@ defineExpose({
|
|||||||
</Transition>
|
</Transition>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
ref="contentRef"
|
ref="contentRef"
|
||||||
|
@animationend="onAnimationEnd"
|
||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
VxeSelect,
|
VxeSelect,
|
||||||
VxeTooltip,
|
VxeTooltip,
|
||||||
VxeUI,
|
VxeUI,
|
||||||
|
VxeUpload,
|
||||||
// VxeSwitch,
|
// VxeSwitch,
|
||||||
// VxeTextarea,
|
// VxeTextarea,
|
||||||
} from 'vxe-pc-ui';
|
} from 'vxe-pc-ui';
|
||||||
@ -92,6 +93,7 @@ export function initVxeTable() {
|
|||||||
// VxeUI.component(VxeSwitch);
|
// VxeUI.component(VxeSwitch);
|
||||||
// VxeUI.component(VxeTextarea);
|
// VxeUI.component(VxeTextarea);
|
||||||
VxeUI.component(VxeTooltip);
|
VxeUI.component(VxeTooltip);
|
||||||
|
VxeUI.component(VxeUpload);
|
||||||
|
|
||||||
isInit = true;
|
isInit = true;
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,16 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
onCancel() {
|
onCancel() {
|
||||||
modalApi.close();
|
modalApi.close();
|
||||||
},
|
},
|
||||||
|
onClosed() {
|
||||||
|
message.info('onClosed:关闭动画结束');
|
||||||
|
},
|
||||||
onConfirm() {
|
onConfirm() {
|
||||||
message.info('onConfirm');
|
message.info('onConfirm');
|
||||||
// modalApi.close();
|
// modalApi.close();
|
||||||
},
|
},
|
||||||
|
onOpened() {
|
||||||
|
message.info('onOpened:打开动画结束');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -31,6 +31,7 @@ const gridOptions: VxeGridProps<RowType> = {
|
|||||||
{ field: 'price', title: 'Price' },
|
{ field: 'price', title: 'Price' },
|
||||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
|
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
|
||||||
],
|
],
|
||||||
|
exportConfig: {},
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
@ -45,7 +46,7 @@ const gridOptions: VxeGridProps<RowType> = {
|
|||||||
},
|
},
|
||||||
toolbarConfig: {
|
toolbarConfig: {
|
||||||
custom: true,
|
custom: true,
|
||||||
// export: true,
|
export: true,
|
||||||
// import: true,
|
// import: true,
|
||||||
refresh: true,
|
refresh: true,
|
||||||
zoom: true,
|
zoom: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user