Vben
2021-03-31 8a14069e71d5393cfa5b758f46a1c5c001fa172b
提交 | 用户 | age
31ff05 1 <template>
V 2   <div :class="getClass">
551fe5 3     <PageHeader
V 4       :ghost="ghost"
9e3ada 5       :title="title"
551fe5 6       v-bind="$attrs"
V 7       ref="headerRef"
9e3ada 8       v-if="content || $slots.headerContent || title || getHeaderSlots.length"
551fe5 9     >
31ff05 10       <template #default>
V 11         <template v-if="content">
12           {{ content }}
13         </template>
9edc28 14         <slot name="headerContent" v-else></slot>
31ff05 15       </template>
V 16       <template #[item]="data" v-for="item in getHeaderSlots">
9edc28 17         <slot :name="item" v-bind="data"></slot>
31ff05 18       </template>
V 19     </PageHeader>
551fe5 20     <div
fcff2c 21       class="overflow-hidden"
551fe5 22       :class="[`${prefixCls}-content`, contentClass]"
V 23       :style="getContentStyle"
24     >
9edc28 25       <slot></slot>
31ff05 26     </div>
V 27     <PageFooter v-if="getShowFooter" ref="footerRef">
28       <template #left>
9edc28 29         <slot name="leftFooter"></slot>
31ff05 30       </template>
V 31       <template #right>
9edc28 32         <slot name="rightFooter"></slot>
31ff05 33       </template>
V 34     </PageFooter>
35   </div>
36 </template>
37 <script lang="ts">
38   import type { CSSProperties, PropType } from 'vue';
39
40   import { defineComponent, computed, watch, nextTick, ref, unref } from 'vue';
41   import PageFooter from './PageFooter.vue';
42   import { usePageContext } from '/@/hooks/component/usePageContext';
43
44   import { useDesign } from '/@/hooks/web/useDesign';
45   import { propTypes } from '/@/utils/propTypes';
46   import { omit } from 'lodash-es';
47   import { PageHeader } from 'ant-design-vue';
0fe42a 48   import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
31ff05 49   export default defineComponent({
V 50     name: 'PageWrapper',
51     components: { PageFooter, PageHeader },
b93f20 52     inheritAttrs: false,
31ff05 53     props: {
9e3ada 54       title: propTypes.string,
31ff05 55       dense: propTypes.bool,
V 56       ghost: propTypes.bool,
57       content: propTypes.string,
58       contentStyle: {
59         type: Object as PropType<CSSProperties>,
60       },
de5bf7 61       contentBackground: propTypes.bool,
31ff05 62       contentFullHeight: propTypes.bool,
551fe5 63       contentClass: propTypes.string,
V 64       fixedHeight: propTypes.bool,
31ff05 65     },
V 66     setup(props, { slots }) {
67       const headerRef = ref<ComponentRef>(null);
68       const footerRef = ref<ComponentRef>(null);
6392b7 69       const footerHeight = ref(0);
53867a 70       const { prefixCls, prefixVar } = useDesign('page-wrapper');
31ff05 71       const { contentHeight, setPageHeight, pageHeight } = usePageContext();
V 72
73       const getClass = computed(() => {
74         return [
75           prefixCls,
76           {
77             [`${prefixCls}--dense`]: props.dense,
78           },
79         ];
80       });
81
82       const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
83
84       const getHeaderSlots = computed(() => {
85         return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
86       });
87
88       const getContentStyle = computed(
89         (): CSSProperties => {
551fe5 90           const { contentBackground, contentFullHeight, contentStyle, fixedHeight } = props;
de5bf7 91           const bg = contentBackground ? { backgroundColor: '#fff' } : {};
31ff05 92           if (!contentFullHeight) {
V 93             return { ...bg, ...contentStyle };
94           }
551fe5 95           const height = `${unref(pageHeight)}px`;
31ff05 96           return {
V 97             ...bg,
98             ...contentStyle,
551fe5 99             minHeight: height,
V 100             ...(fixedHeight ? { height } : {}),
6392b7 101             paddingBottom: `${unref(footerHeight)}px`,
31ff05 102           };
V 103         }
104       );
105
106       watch(
6392b7 107         () => [contentHeight?.value, getShowFooter.value],
V 108         () => {
0fe42a 109           calcContentHeight();
31ff05 110         },
V 111         {
53867a 112           flush: 'post',
31ff05 113           immediate: true,
V 114         }
115       );
116
0fe42a 117       onMountedOrActivated(() => {
Z 118         nextTick(() => {
119           calcContentHeight();
120         });
121       });
122
123       function calcContentHeight() {
124         if (!props.contentFullHeight) {
125           return;
126         }
127         //fix:in contentHeight mode: delay getting footer and header dom element to get the correct height
128         const footer = unref(footerRef);
129         const header = unref(headerRef);
130         footerHeight.value = 0;
131         const footerEl = footer?.$el;
132
133         if (footerEl) {
134           footerHeight.value += footerEl?.offsetHeight ?? 0;
135         }
136         let headerHeight = 0;
137         const headerEl = header?.$el;
138         if (headerEl) {
139           headerHeight += headerEl?.offsetHeight ?? 0;
140         }
141         // fix:subtract content's marginTop and marginBottom value
142         let subtractHeight = 0;
143         let marginBottom = '0px';
144         let marginTop = '0px';
145         const classElments = document.querySelectorAll(`.${prefixVar}-page-wrapper-content`);
146         if (classElments && classElments.length > 0) {
147           const contentEl = classElments[0];
148           const cssStyle = getComputedStyle(contentEl);
149           marginBottom = cssStyle?.marginBottom;
150           marginTop = cssStyle?.marginTop;
151         }
152         if (marginBottom) {
153           const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));
154           subtractHeight += contentMarginBottom;
155         }
156         if (marginTop) {
157           const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));
158           subtractHeight += contentMarginTop;
159         }
160         setPageHeight?.(unref(contentHeight) - unref(footerHeight) - headerHeight - subtractHeight);
161       }
162
31ff05 163       return {
V 164         getContentStyle,
165         footerRef,
166         headerRef,
167         getClass,
168         getHeaderSlots,
169         prefixCls,
170         getShowFooter,
171         pageHeight,
172         omit,
173       };
174     },
175   });
176 </script>
177 <style lang="less">
178   @prefix-cls: ~'@{namespace}-page-wrapper';
179
180   .@{prefix-cls} {
181     position: relative;
182
fcff2c 183     .@{prefix-cls}-content {
8a1406 184       margin: 16px;
fcff2c 185     }
53867a 186
31ff05 187     .ant-page-header {
V 188       &:empty {
189         padding: 0;
190       }
191     }
192
193     &--dense {
194       .@{prefix-cls}-content {
195         margin: 0;
196       }
197     }
198   }
199 </style>