blob: 52c8b5eb8bd12b097fb7045d6402b3a424d06405 [file] [log] [blame]
<template>
<ScrollContainer ref="wrapperRef">
<div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
<slot></slot>
</div>
</ScrollContainer>
</template>
<script lang="ts">
import type { CSSProperties } from 'vue';
import {
defineComponent,
computed,
ref,
watchEffect,
unref,
watch,
onMounted,
nextTick,
onUnmounted,
} from 'vue';
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
import { ScrollContainer } from '/@/components/Container';
import { createModalContext } from '../hooks/useModalContext';
import { useMutationObserver } from '@vueuse/core';
const props = {
loading: { type: Boolean },
useWrapper: { type: Boolean, default: true },
modalHeaderHeight: { type: Number, default: 57 },
modalFooterHeight: { type: Number, default: 74 },
minHeight: { type: Number, default: 200 },
height: { type: Number },
footerOffset: { type: Number, default: 0 },
visible: { type: Boolean },
fullScreen: { type: Boolean },
loadingTip: { type: String },
};
export default defineComponent({
name: 'ModalWrapper',
components: { ScrollContainer },
inheritAttrs: false,
props,
emits: ['height-change', 'ext-height'],
setup(props, { emit }) {
const wrapperRef = ref<ComponentRef>(null);
const spinRef = ref<ElRef>(null);
const realHeightRef = ref(0);
const minRealHeightRef = ref(0);
let realHeight = 0;
let stopElResizeFn: Fn = () => {};
useWindowSizeFn(setModalHeight.bind(null));
useMutationObserver(
spinRef,
() => {
setModalHeight();
},
{
attributes: true,
subtree: true,
},
);
createModalContext({
redoModalHeight: setModalHeight,
});
const spinStyle = computed((): CSSProperties => {
return {
minHeight: `${props.minHeight}px`,
[props.fullScreen ? 'height' : 'maxHeight']: `${unref(realHeightRef)}px`,
};
});
watchEffect(() => {
props.useWrapper && setModalHeight();
});
watch(
() => props.fullScreen,
(v) => {
setModalHeight();
if (!v) {
realHeightRef.value = minRealHeightRef.value;
} else {
minRealHeightRef.value = realHeightRef.value;
}
},
);
onMounted(() => {
const { modalHeaderHeight, modalFooterHeight } = props;
emit('ext-height', modalHeaderHeight + modalFooterHeight);
});
onUnmounted(() => {
stopElResizeFn && stopElResizeFn();
});
async function scrollTop() {
nextTick(() => {
const wrapperRefDom = unref(wrapperRef);
if (!wrapperRefDom) return;
(wrapperRefDom as any)?.scrollTo?.(0);
});
}
async function setModalHeight() {
// Fixed that the monitoring still exists when the pop-up window is closed, causing the pop-up window to open again without height
// Add this, you must pass the parent's visible when using it
if (!props.visible) return;
const wrapperRefDom = unref(wrapperRef);
if (!wrapperRefDom) return;
const bodyDom = wrapperRefDom.$el.parentElement;
if (!bodyDom) return;
bodyDom.style.padding = '0';
await nextTick();
try {
const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
if (!modalDom) return;
const modalRect = getComputedStyle(modalDom as Element).top;
const modalTop = Number.parseInt(modalRect);
let maxHeight =
window.innerHeight -
modalTop * 2 +
(props.footerOffset! || 0) -
props.modalFooterHeight -
props.modalHeaderHeight;
// Scroll bar will appear if you are too far from the top
if (modalTop < 40) {
maxHeight -= 26;
}
await nextTick();
const spinEl = unref(spinRef);
if (!spinEl) return;
await nextTick();
// if (!realHeight) {
realHeight = spinEl.scrollHeight;
// }
if (props.fullScreen) {
realHeightRef.value =
window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 28;
} else {
realHeightRef.value = props.height
? props.height
: realHeight > maxHeight
? maxHeight
: realHeight;
}
emit('height-change', unref(realHeightRef));
} catch (error) {
console.log(error);
}
}
return { wrapperRef, spinRef, spinStyle, scrollTop, setModalHeight };
},
});
</script>