vben
2021-01-06 144ab577da06ff0bd1f258d1901b87864f232e45
提交 | 用户 | age
ebf7c8 1 <template>
V 2   <ScrollContainer ref="wrapperRef" :style="wrapStyle">
3     <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
4       <slot />
5     </div>
6   </ScrollContainer>
7 </template>
8 <script lang="ts">
9   import type { ModalWrapperProps } from '../types';
10   import type { CSSProperties } from 'vue';
11
12   import {
13     defineComponent,
14     computed,
15     ref,
16     watchEffect,
17     unref,
18     watch,
19     onMounted,
20     nextTick,
21     onUnmounted,
22   } from 'vue';
23   import { Spin } from 'ant-design-vue';
24
25   import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
26   import { ScrollContainer } from '/@/components/Container';
27
28   // import { useElResize } from '/@/hooks/event/useElResize';
29   import { propTypes } from '/@/utils/propTypes';
30   import { createModalContext } from '../hooks/useModalContext';
31
32   export default defineComponent({
33     name: 'ModalWrapper',
144ab5 34     inheritAttrs: false,
ebf7c8 35     components: { Spin, ScrollContainer },
V 36     props: {
37       loading: propTypes.bool,
38       useWrapper: propTypes.bool.def(true),
39       modalHeaderHeight: propTypes.number.def(50),
40       modalFooterHeight: propTypes.number.def(54),
41       minHeight: propTypes.number.def(200),
5091a8 42       height: propTypes.number,
ebf7c8 43       footerOffset: propTypes.number.def(0),
V 44       visible: propTypes.bool,
45       fullScreen: propTypes.bool,
46       loadingTip: propTypes.string,
47     },
48     emits: ['height-change', 'ext-height'],
49     setup(props: ModalWrapperProps, { emit }) {
50       const wrapperRef = ref<ComponentRef>(null);
51       const spinRef = ref<ElRef>(null);
52       const realHeightRef = ref(0);
3b126e 53       const minRealHeightRef = ref(0);
144ab5 54
V 55       let realHeight = 0;
ebf7c8 56
V 57       let stopElResizeFn: Fn = () => {};
58
59       useWindowSizeFn(setModalHeight);
60
61       createModalContext({
62         redoModalHeight: setModalHeight,
63       });
64
65       const wrapStyle = computed(
66         (): CSSProperties => {
67           return {
68             minHeight: `${props.minHeight}px`,
69             height: `${unref(realHeightRef)}px`,
70             // overflow: 'auto',
71           };
72         }
73       );
74
75       const spinStyle = computed(
76         (): CSSProperties => {
77           return {
78             // padding 28
79             height: `${unref(realHeightRef) - 28}px`,
80           };
81         }
82       );
83
84       watchEffect(() => {
85         props.useWrapper && setModalHeight();
86       });
87
88       watch(
89         () => props.fullScreen,
3b126e 90         (v) => {
V 91           setModalHeight();
92           if (!v) {
93             realHeightRef.value = minRealHeightRef.value;
94           } else {
95             minRealHeightRef.value = realHeightRef.value;
96           }
ebf7c8 97         }
V 98       );
99
100       onMounted(() => {
101         const { modalHeaderHeight, modalFooterHeight } = props;
102         emit('ext-height', modalHeaderHeight + modalFooterHeight);
103         // listenElResize();
104       });
105
106       onUnmounted(() => {
107         stopElResizeFn && stopElResizeFn();
108       });
109
110       async function setModalHeight() {
111         // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
112         // 加上这个,就必须在使用的时候传递父级的visible
113         if (!props.visible) return;
114         const wrapperRefDom = unref(wrapperRef);
115         if (!wrapperRefDom) return;
116         const bodyDom = wrapperRefDom.$el.parentElement;
117         if (!bodyDom) return;
118         bodyDom.style.padding = '0';
119         await nextTick();
120
121         try {
122           const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement;
123           if (!modalDom) return;
124
125           const modalRect = getComputedStyle(modalDom).top;
126           const modalTop = Number.parseInt(modalRect);
127           let maxHeight =
128             window.innerHeight -
129             modalTop * 2 +
130             (props.footerOffset! || 0) -
131             props.modalFooterHeight -
132             props.modalHeaderHeight;
133
134           // 距离顶部过进会出现滚动条
135           if (modalTop < 40) {
136             maxHeight -= 26;
137           }
138           await nextTick();
139           const spinEl = unref(spinRef);
140
141           if (!spinEl) return;
142
144ab5 143           if (!realHeight) {
V 144             realHeight = spinEl.scrollHeight;
145           }
ebf7c8 146           if (props.fullScreen) {
V 147             realHeightRef.value =
148               window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight;
149           } else {
5091a8 150             realHeightRef.value = props.height
V 151               ? props.height
152               : realHeight > maxHeight
153               ? maxHeight
144ab5 154               : realHeight + 46;
ebf7c8 155           }
V 156           emit('height-change', unref(realHeightRef));
157         } catch (error) {
158           console.log(error);
159         }
160       }
161
162       return { wrapStyle, wrapperRef, spinRef, spinStyle };
163     },
164   });
165 </script>