123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- <template>
- <div :class="getClass" ref="wrapperRef">
- <PageHeader
- :ghost="ghost"
- :title="title"
- v-bind="omit($attrs, 'class')"
- :style="getHeaderStyle"
- ref="headerRef"
- v-if="getShowHeader"
- >
- <template #default>
- <template v-if="content">
- {{ content }}
- </template>
- <slot name="headerContent" v-else></slot>
- </template>
- <template #[item]="data" v-for="item in getHeaderSlots">
- <slot :name="item" v-bind="data || {}"></slot>
- </template>
- </PageHeader>
- <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
- <slot></slot>
- </div>
- <PageFooter v-if="getShowFooter" ref="footerRef">
- <template #left>
- <slot name="leftFooter"></slot>
- </template>
- <template #right>
- <slot name="rightFooter"></slot>
- </template>
- </PageFooter>
- </div>
- </template>
- <script lang="ts" setup>
- import { PageWrapperFixedHeightKey } from '@/enums/pageEnum';
- import { useContentHeight } from '@/hooks/web/useContentHeight';
- import { useDesign } from '@/hooks/web/useDesign';
- import { propTypes } from '@/utils/propTypes';
- import { PageHeader } from 'ant-design-vue';
- import { omit } from 'lodash-es';
- import {
- CSSProperties,
- PropType,
- computed,
- provide,
- ref,
- unref,
- useAttrs,
- useSlots,
- watch,
- } from 'vue';
- import PageFooter from './PageFooter.vue';
- defineOptions({
- name: 'PageWrapper',
- inheritAttrs: false,
- });
- const props = defineProps({
- title: propTypes.string,
- dense: propTypes.bool,
- ghost: propTypes.bool,
- headerSticky: propTypes.bool,
- headerStyle: Object as PropType<CSSProperties>,
- content: propTypes.string,
- contentStyle: {
- type: Object as PropType<CSSProperties>,
- },
- contentBackground: propTypes.bool,
- contentFullHeight: propTypes.bool.def(false),
- contentClass: propTypes.string,
- fixedHeight: propTypes.bool,
- upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
- });
- const attrs = useAttrs();
- const slots = useSlots();
- const wrapperRef = ref(null);
- const headerRef = ref(null);
- const contentRef = ref(null);
- const footerRef = ref(null);
- const { prefixCls } = useDesign('page-wrapper');
- provide(
- PageWrapperFixedHeightKey,
- computed(() => props.fixedHeight),
- );
- const getIsContentFullHeight = computed(() => {
- return props.contentFullHeight;
- });
- const getUpwardSpace = computed(() => props.upwardSpace);
- const { redoHeight, setCompensation, contentHeight } = useContentHeight(
- getIsContentFullHeight,
- wrapperRef,
- [headerRef, footerRef],
- [contentRef],
- getUpwardSpace,
- );
- setCompensation({ useLayoutFooter: true, elements: [footerRef] });
- const getClass = computed(() => {
- return [
- prefixCls,
- {
- [`${prefixCls}--dense`]: props.dense,
- },
- attrs.class ?? {},
- ];
- });
- const getHeaderStyle = computed((): CSSProperties => {
- const { headerSticky } = props;
- if (!headerSticky) {
- return {};
- }
- return {
- position: 'sticky',
- top: 0,
- zIndex: 99,
- ...props.headerStyle,
- };
- });
- const getShowHeader = computed(
- () => props.content || slots?.headerContent || props.title || getHeaderSlots.value.length,
- );
- const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
- const getHeaderSlots = computed(() => {
- return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'));
- });
- const getContentStyle = computed((): CSSProperties => {
- const { contentFullHeight, contentStyle, fixedHeight } = props;
- if (!contentFullHeight) {
- return { ...contentStyle };
- }
- const height = `${unref(contentHeight)}px`;
- return {
- ...contentStyle,
- minHeight: height,
- ...(fixedHeight ? { height } : {}),
- };
- });
- const getContentClass = computed(() => {
- const { contentBackground, contentClass } = props;
- return [
- `${prefixCls}-content`,
- contentClass,
- {
- [`${prefixCls}-content-bg`]: contentBackground,
- },
- ];
- });
- watch(
- () => [getShowFooter.value],
- () => {
- redoHeight();
- },
- {
- flush: 'post',
- immediate: true,
- },
- );
- </script>
- <style lang="less">
- @prefix-cls: ~'@{namespace}-page-wrapper';
- .@{prefix-cls} {
- position: relative;
- .@{prefix-cls}-content {
- margin: 16px;
- }
- .ant-page-header {
- &:empty {
- padding: 0;
- }
- }
- &-content-bg {
- background-color: @component-background;
- }
- &--dense {
- .@{prefix-cls}-content {
- margin: 0;
- }
- }
- }
- </style>
|