feat: support unlocking scroll when modal dialog closes
This commit is contained in:
@@ -5,9 +5,8 @@ import type { HTMLAttributes } from 'vue';
|
||||
|
||||
import type { ClassType } from '@vben-core/typings';
|
||||
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useScrollLock } from '@vben-core/composables';
|
||||
import { cn } from '@vben-core/shared/utils';
|
||||
|
||||
import { X } from '@lucide/vue';
|
||||
@@ -18,6 +17,8 @@ import {
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui';
|
||||
|
||||
import DialogOverlay from './DialogOverlay.vue';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
@@ -73,11 +74,9 @@ const position = computed(() => {
|
||||
return isAppendToBody() ? 'fixed' : 'absolute';
|
||||
});
|
||||
|
||||
// reka-ui 的 Dialog 在 modal=false 时不会渲染遮罩,这里自行渲染一个遮罩层并锁定滚动,
|
||||
// 既保留遮罩/滚动锁定能力,又避免 modal=true 时 body 被设置 pointer-events:none 导致
|
||||
// 弹出层(如 Select 下拉框)无法点击的问题。
|
||||
useScrollLock();
|
||||
const dismissableModalId = inject('DISMISSABLE_MODAL_ID', undefined);
|
||||
// reka-ui 的 Dialog 在 modal=false 时不会渲染遮罩,这里通过 DialogOverlay 组件自行渲染遮罩层并锁定滚动。
|
||||
// DialogOverlay 组件通过 v-if 控制挂载/卸载,其内部的 useScrollLock 会在组件卸载时自动解锁滚动,
|
||||
// 避免 modal=true 时 body 被设置 pointer-events:none 导致弹出层(如 Select 下拉框)无法点击的问题。
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
|
||||
@@ -100,18 +99,13 @@ defineExpose({
|
||||
<template>
|
||||
<DialogPortal :to="appendTo">
|
||||
<Transition name="fade">
|
||||
<div
|
||||
<DialogOverlay
|
||||
v-if="open && modal"
|
||||
:data-dismissable-modal="dismissableModalId"
|
||||
:style="{
|
||||
...(zIndex ? { zIndex } : {}),
|
||||
position,
|
||||
backdropFilter:
|
||||
overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',
|
||||
}"
|
||||
:class="cn('z-popup bg-overlay inset-0 fixed')"
|
||||
:overlay-blur="overlayBlur"
|
||||
:position="position"
|
||||
:z-index="zIndex"
|
||||
@click="() => emits('close')"
|
||||
></div>
|
||||
/>
|
||||
</Transition>
|
||||
<DialogContent
|
||||
ref="contentRef"
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogOverlayProps } from 'reka-ui';
|
||||
|
||||
import type { HTMLAttributes } from 'vue';
|
||||
import { inject } from 'vue';
|
||||
|
||||
import { useScrollLock } from '@vben-core/composables';
|
||||
import { cn } from '@vben-core/shared/utils';
|
||||
|
||||
import { reactiveOmit } from '@vueuse/core';
|
||||
import { DialogOverlay } from 'reka-ui';
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
class?: any;
|
||||
overlayBlur?: number;
|
||||
position?: 'absolute' | 'fixed';
|
||||
zIndex?: number;
|
||||
}>(),
|
||||
{
|
||||
position: 'fixed',
|
||||
},
|
||||
);
|
||||
|
||||
const props = defineProps<
|
||||
DialogOverlayProps & { class?: HTMLAttributes['class'] }
|
||||
>();
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class');
|
||||
useScrollLock();
|
||||
const dismissableModalId = inject('DISMISSABLE_MODAL_ID', undefined);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogOverlay
|
||||
data-slot="dialog-overlay"
|
||||
v-bind="delegatedProps"
|
||||
:class="
|
||||
cn(
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot></slot>
|
||||
</DialogOverlay>
|
||||
<div
|
||||
:data-dismissable-modal="dismissableModalId"
|
||||
:style="{
|
||||
...(zIndex ? { zIndex } : {}),
|
||||
position,
|
||||
backdropFilter:
|
||||
overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',
|
||||
}"
|
||||
:class="cn('z-popup bg-overlay inset-0 fixed', props.class)"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user