Skip to content

Commit 1a9b050

Browse files
author
 panda7
committed
feat: add animation effects to VbenModal component
1 parent 1bc5d29 commit 1a9b050

File tree

6 files changed

+67
-2
lines changed

6 files changed

+67
-2
lines changed

docs/src/components/common-ui/vben-modal.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ Modal 内的内容一般业务中,会比较复杂,所以我们可以将 moda
5656

5757
<DemoPreview dir="demos/vben-modal/shared-data" />
5858

59+
## 动画类型
60+
61+
通过 `animationType` 属性可以控制弹窗的动画效果:
62+
63+
- `slide`(默认):从顶部向下滑动进入/退出
64+
- `scale`:缩放淡入/淡出效果
65+
66+
<DemoPreview dir="demos/vben-modal/animation-type" />
67+
5968
::: info 注意
6069

6170
- `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
@@ -112,6 +121,7 @@ const [Modal, modalApi] = useVbenModal({
112121
| bordered | 是否显示border | `boolean` | `false` |
113122
| zIndex | 弹窗的ZIndex层级 | `number` | `1000` |
114123
| overlayBlur | 遮罩模糊度 | `number` | - |
124+
| animationType | 动画类型 | `'slide' \| 'scale'` | `'slide'` |
115125
| submitting | 标记为提交中,锁定弹窗当前状态 | `boolean` | `false` |
116126

117127
::: info appendToMain
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script lang="ts" setup>
2+
import { useVbenModal, VbenButton } from '@vben/common-ui';
3+
4+
const [SlideModal, slideModalApi] = useVbenModal({
5+
animationType: 'slide',
6+
});
7+
8+
const [ScaleModal, scaleModalApi] = useVbenModal({
9+
animationType: 'scale',
10+
});
11+
12+
function openSlideModal() {
13+
slideModalApi.open();
14+
}
15+
16+
function openScaleModal() {
17+
scaleModalApi.open();
18+
}
19+
</script>
20+
21+
<template>
22+
<div class="space-y-4">
23+
<div class="flex gap-4">
24+
<VbenButton @click="openSlideModal">滑动动画</VbenButton>
25+
<VbenButton @click="openScaleModal">缩放动画</VbenButton>
26+
</div>
27+
28+
<SlideModal title="滑动动画示例" class="w-[500px]">
29+
<p>这是使用滑动动画的弹窗,从顶部向下滑动进入。</p>
30+
</SlideModal>
31+
32+
<ScaleModal title="缩放动画示例" class="w-[500px]">
33+
<p>这是使用缩放动画的弹窗,以缩放淡入淡出的方式显示。</p>
34+
</ScaleModal>
35+
</div>
36+
</template>

packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class ModalApi {
5959
showCancelButton: true,
6060
showConfirmButton: true,
6161
title: '',
62+
animationType: 'slide',
6263
};
6364

6465
this.store = new Store<ModalState>(

packages/@core/ui-kit/popup-ui/src/modal/modal.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import type { MaybePromise } from '@vben-core/typings';
55
import type { ModalApi } from './modal-api';
66

77
export interface ModalProps {
8+
/**
9+
* 动画类型
10+
* @default 'slide'
11+
*/
12+
animationType?: 'scale' | 'slide';
813
/**
914
* 是否要挂载到内容区域
1015
* @default false

packages/@core/ui-kit/popup-ui/src/modal/modal.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const {
9494
submitting,
9595
title,
9696
titleTooltip,
97+
animationType,
9798
zIndex,
9899
} = usePriorityValues(props, state);
99100
@@ -244,6 +245,7 @@ function handleClosed() {
244245
:modal="modal"
245246
:open="state?.isOpen"
246247
:show-close="closable"
248+
:animation-type="animationType"
247249
:z-index="zIndex"
248250
:overlay-blur="overlayBlur"
249251
close-class="top-3"

packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import DialogOverlay from './DialogOverlay.vue';
2020
const props = withDefaults(
2121
defineProps<
2222
DialogContentProps & {
23+
animationType?: 'scale' | 'slide';
2324
appendTo?: HTMLElement | string;
2425
class?: ClassType;
2526
closeClass?: ClassType;
@@ -31,7 +32,12 @@ const props = withDefaults(
3132
zIndex?: number;
3233
}
3334
>(),
34-
{ appendTo: 'body', closeDisabled: false, showClose: true },
35+
{
36+
appendTo: 'body',
37+
animationType: 'slide',
38+
closeDisabled: false,
39+
showClose: true,
40+
},
3541
);
3642
const emits = defineEmits<
3743
DialogContentEmits & { close: []; closed: []; opened: [] }
@@ -43,6 +49,7 @@ const delegatedProps = computed(() => {
4349
modal: _modal,
4450
open: _open,
4551
showClose: __,
52+
animationType: ___,
4653
...delegated
4754
} = props;
4855
@@ -100,7 +107,11 @@ defineExpose({
100107
v-bind="forwarded"
101108
:class="
102109
cn(
103-
'z-popup bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] w-full p-6 shadow-lg outline-none sm:rounded-xl',
110+
'z-popup bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 w-full p-6 shadow-lg outline-none sm:rounded-xl',
111+
{
112+
'data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]':
113+
animationType === 'slide',
114+
},
104115
props.class,
105116
)
106117
"

0 commit comments

Comments
 (0)