mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-22 22:16:18 +08:00
feat: add animation effects to VbenModal component
This commit is contained in:
@@ -56,6 +56,15 @@ Modal 内的内容一般业务中,会比较复杂,所以我们可以将 moda
|
|||||||
|
|
||||||
<DemoPreview dir="demos/vben-modal/shared-data" />
|
<DemoPreview dir="demos/vben-modal/shared-data" />
|
||||||
|
|
||||||
|
## 动画类型
|
||||||
|
|
||||||
|
通过 `animationType` 属性可以控制弹窗的动画效果:
|
||||||
|
|
||||||
|
- `slide`(默认):从顶部向下滑动进入/退出
|
||||||
|
- `scale`:缩放淡入/淡出效果
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-modal/animation-type" />
|
||||||
|
|
||||||
::: info 注意
|
::: info 注意
|
||||||
|
|
||||||
- `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
|
- `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
|
||||||
@@ -112,6 +121,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
| bordered | 是否显示border | `boolean` | `false` |
|
| bordered | 是否显示border | `boolean` | `false` |
|
||||||
| zIndex | 弹窗的ZIndex层级 | `number` | `1000` |
|
| zIndex | 弹窗的ZIndex层级 | `number` | `1000` |
|
||||||
| overlayBlur | 遮罩模糊度 | `number` | - |
|
| overlayBlur | 遮罩模糊度 | `number` | - |
|
||||||
|
| animationType | 动画类型 | `'slide' \| 'scale'` | `'slide'` |
|
||||||
| submitting | 标记为提交中,锁定弹窗当前状态 | `boolean` | `false` |
|
| submitting | 标记为提交中,锁定弹窗当前状态 | `boolean` | `false` |
|
||||||
|
|
||||||
::: info appendToMain
|
::: info appendToMain
|
||||||
|
36
docs/src/demos/vben-modal/animation-type/index.vue
Normal file
36
docs/src/demos/vben-modal/animation-type/index.vue
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const [SlideModal, slideModalApi] = useVbenModal({
|
||||||
|
animationType: 'slide',
|
||||||
|
});
|
||||||
|
|
||||||
|
const [ScaleModal, scaleModalApi] = useVbenModal({
|
||||||
|
animationType: 'scale',
|
||||||
|
});
|
||||||
|
|
||||||
|
function openSlideModal() {
|
||||||
|
slideModalApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openScaleModal() {
|
||||||
|
scaleModalApi.open();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<VbenButton @click="openSlideModal">滑动动画</VbenButton>
|
||||||
|
<VbenButton @click="openScaleModal">缩放动画</VbenButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SlideModal title="滑动动画示例" class="w-[500px]">
|
||||||
|
<p>这是使用滑动动画的弹窗,从顶部向下滑动进入。</p>
|
||||||
|
</SlideModal>
|
||||||
|
|
||||||
|
<ScaleModal title="缩放动画示例" class="w-[500px]">
|
||||||
|
<p>这是使用缩放动画的弹窗,以缩放淡入淡出的方式显示。</p>
|
||||||
|
</ScaleModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
@@ -59,6 +59,7 @@ export class ModalApi {
|
|||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
showConfirmButton: true,
|
showConfirmButton: true,
|
||||||
title: '',
|
title: '',
|
||||||
|
animationType: 'slide',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.store = new Store<ModalState>(
|
this.store = new Store<ModalState>(
|
||||||
|
@@ -5,6 +5,11 @@ import type { MaybePromise } from '@vben-core/typings';
|
|||||||
import type { ModalApi } from './modal-api';
|
import type { ModalApi } from './modal-api';
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
|
/**
|
||||||
|
* 动画类型
|
||||||
|
* @default 'slide'
|
||||||
|
*/
|
||||||
|
animationType?: 'scale' | 'slide';
|
||||||
/**
|
/**
|
||||||
* 是否要挂载到内容区域
|
* 是否要挂载到内容区域
|
||||||
* @default false
|
* @default false
|
||||||
|
@@ -94,6 +94,7 @@ const {
|
|||||||
submitting,
|
submitting,
|
||||||
title,
|
title,
|
||||||
titleTooltip,
|
titleTooltip,
|
||||||
|
animationType,
|
||||||
zIndex,
|
zIndex,
|
||||||
} = usePriorityValues(props, state);
|
} = usePriorityValues(props, state);
|
||||||
|
|
||||||
@@ -244,6 +245,7 @@ function handleClosed() {
|
|||||||
:modal="modal"
|
:modal="modal"
|
||||||
:open="state?.isOpen"
|
:open="state?.isOpen"
|
||||||
:show-close="closable"
|
:show-close="closable"
|
||||||
|
:animation-type="animationType"
|
||||||
:z-index="zIndex"
|
:z-index="zIndex"
|
||||||
:overlay-blur="overlayBlur"
|
:overlay-blur="overlayBlur"
|
||||||
close-class="top-3"
|
close-class="top-3"
|
||||||
|
@@ -20,6 +20,7 @@ import DialogOverlay from './DialogOverlay.vue';
|
|||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<
|
defineProps<
|
||||||
DialogContentProps & {
|
DialogContentProps & {
|
||||||
|
animationType?: 'scale' | 'slide';
|
||||||
appendTo?: HTMLElement | string;
|
appendTo?: HTMLElement | string;
|
||||||
class?: ClassType;
|
class?: ClassType;
|
||||||
closeClass?: ClassType;
|
closeClass?: ClassType;
|
||||||
@@ -31,7 +32,12 @@ const props = withDefaults(
|
|||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
}
|
}
|
||||||
>(),
|
>(),
|
||||||
{ appendTo: 'body', closeDisabled: false, showClose: true },
|
{
|
||||||
|
appendTo: 'body',
|
||||||
|
animationType: 'slide',
|
||||||
|
closeDisabled: false,
|
||||||
|
showClose: true,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const emits = defineEmits<
|
const emits = defineEmits<
|
||||||
DialogContentEmits & { close: []; closed: []; opened: [] }
|
DialogContentEmits & { close: []; closed: []; opened: [] }
|
||||||
@@ -43,6 +49,7 @@ const delegatedProps = computed(() => {
|
|||||||
modal: _modal,
|
modal: _modal,
|
||||||
open: _open,
|
open: _open,
|
||||||
showClose: __,
|
showClose: __,
|
||||||
|
animationType: ___,
|
||||||
...delegated
|
...delegated
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -100,7 +107,11 @@ defineExpose({
|
|||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'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',
|
'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',
|
||||||
|
{
|
||||||
|
'data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]':
|
||||||
|
animationType === 'slide',
|
||||||
|
},
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
Reference in New Issue
Block a user