vben
2021-08-24 56a966cfbf8db5b29a42185f0f25a0e800c30dbb
提交 | 用户 | age
31ff05 1 <template>
4d8e39 2   <div :class="getClass" ref="wrapperRef">
551fe5 3     <PageHeader
V 4       :ghost="ghost"
9e3ada 5       :title="title"
8879ae 6       v-bind="omit($attrs, 'class')"
551fe5 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">
b1f317 17         <slot :name="item" v-bind="data || {}"></slot>
31ff05 18       </template>
V 19     </PageHeader>
566280 20
4d8e39 21     <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
9edc28 22       <slot></slot>
31ff05 23     </div>
566280 24
31ff05 25     <PageFooter v-if="getShowFooter" ref="footerRef">
V 26       <template #left>
9edc28 27         <slot name="leftFooter"></slot>
31ff05 28       </template>
V 29       <template #right>
9edc28 30         <slot name="rightFooter"></slot>
31ff05 31       </template>
V 32     </PageFooter>
33   </div>
34 </template>
35 <script lang="ts">
da12da 36   import { CSSProperties, PropType, provide } from 'vue';
31ff05 37
4d8e39 38   import { defineComponent, computed, watch, ref, unref } from 'vue';
31ff05 39   import PageFooter from './PageFooter.vue';
V 40
41   import { useDesign } from '/@/hooks/web/useDesign';
42   import { propTypes } from '/@/utils/propTypes';
43   import { omit } from 'lodash-es';
44   import { PageHeader } from 'ant-design-vue';
9de6ac 45   import { useContentHeight } from '/@/hooks/web/useContentHeight';
da12da 46   import { PageWrapperFixedHeightKey } from '..';
33cd8f 47
31ff05 48   export default defineComponent({
V 49     name: 'PageWrapper',
50     components: { PageFooter, PageHeader },
b93f20 51     inheritAttrs: false,
31ff05 52     props: {
9e3ada 53       title: propTypes.string,
31ff05 54       dense: propTypes.bool,
V 55       ghost: propTypes.bool,
56       content: propTypes.string,
57       contentStyle: {
58         type: Object as PropType<CSSProperties>,
59       },
de5bf7 60       contentBackground: propTypes.bool,
31ff05 61       contentFullHeight: propTypes.bool,
551fe5 62       contentClass: propTypes.string,
V 63       fixedHeight: propTypes.bool,
31ff05 64     },
8879ae 65     setup(props, { slots, attrs }) {
9de6ac 66       const wrapperRef = ref(null);
L 67       const headerRef = ref(null);
68       const contentRef = ref(null);
69       const footerRef = ref(null);
4d8e39 70       const { prefixCls } = useDesign('page-wrapper');
L 71
da12da 72       provide(
73         PageWrapperFixedHeightKey,
56a966 74         computed(() => props.fixedHeight),
da12da 75       );
76
9de6ac 77       const getIsContentFullHeight = computed(() => {
L 78         return props.contentFullHeight;
4d8e39 79       });
L 80
9de6ac 81       const { redoHeight, setCompensation, contentHeight } = useContentHeight(
L 82         getIsContentFullHeight,
4d8e39 83         wrapperRef,
9de6ac 84         [headerRef, footerRef],
56a966 85         [contentRef],
4d8e39 86       );
9de6ac 87       setCompensation({ useLayoutFooter: true, elements: [footerRef] });
31ff05 88
V 89       const getClass = computed(() => {
90         return [
91           prefixCls,
92           {
93             [`${prefixCls}--dense`]: props.dense,
94           },
8879ae 95           attrs.class ?? {},
31ff05 96         ];
V 97       });
98
99       const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
100
101       const getHeaderSlots = computed(() => {
102         return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
103       });
104
566280 105       const getContentStyle = computed((): CSSProperties => {
V 106         const { contentFullHeight, contentStyle, fixedHeight } = props;
107         if (!contentFullHeight) {
108           return { ...contentStyle };
31ff05 109         }
4d8e39 110
L 111         const height = `${unref(contentHeight)}px`;
566280 112         return {
V 113           ...contentStyle,
114           minHeight: height,
115           ...(fixedHeight ? { height } : {}),
116         };
117       });
5b8eb4 118
V 119       const getContentClass = computed(() => {
120         const { contentBackground, contentClass } = props;
121         return [
122           `${prefixCls}-content`,
123           contentClass,
124           {
125             [`${prefixCls}-content-bg`]: contentBackground,
126           },
127         ];
128       });
31ff05 129
V 130       watch(
9de6ac 131         () => [getShowFooter.value],
6392b7 132         () => {
4d8e39 133           redoHeight();
31ff05 134         },
V 135         {
53867a 136           flush: 'post',
31ff05 137           immediate: true,
56a966 138         },
31ff05 139       );
V 140
141       return {
142         getContentStyle,
4d8e39 143         wrapperRef,
31ff05 144         headerRef,
4d8e39 145         contentRef,
L 146         footerRef,
31ff05 147         getClass,
V 148         getHeaderSlots,
149         prefixCls,
150         getShowFooter,
151         omit,
5b8eb4 152         getContentClass,
31ff05 153       };
V 154     },
155   });
156 </script>
157 <style lang="less">
158   @prefix-cls: ~'@{namespace}-page-wrapper';
159
160   .@{prefix-cls} {
161     position: relative;
162
fcff2c 163     .@{prefix-cls}-content {
8a1406 164       margin: 16px;
fcff2c 165     }
53867a 166
31ff05 167     .ant-page-header {
V 168       &:empty {
169         padding: 0;
170       }
171     }
172
5b8eb4 173     &-content-bg {
2cdf2c 174       background-color: @component-background;
5b8eb4 175     }
V 176
31ff05 177     &--dense {
V 178       .@{prefix-cls}-content {
179         margin: 0;
180       }
181     }
182   }
183 </style>