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