Commit 4d8e39857ea59fff99e69832b4a8cabf3a424c24

Authored by Lan
Committed by GitHub
1 parent c4b22a22

perf(pagewrapper): 优化PageWrapper的高度自适应表现使用getViewportOffset替代useContentViewHeight (#792)

Co-authored-by: NorthLan <lan6995@gmail.com>
src/components/Page/src/PageWrapper.vue
1 1 <template>
2   - <div :class="getClass">
  2 + <div :class="getClass" ref="wrapperRef">
3 3 <PageHeader
4 4 :ghost="ghost"
5 5 :title="title"
... ... @@ -18,7 +18,7 @@
18 18 </template>
19 19 </PageHeader>
20 20  
21   - <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle">
  21 + <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
22 22 <slot></slot>
23 23 </div>
24 24  
... ... @@ -35,16 +35,16 @@
35 35 <script lang="ts">
36 36 import type { CSSProperties, PropType } from 'vue';
37 37  
38   - import { defineComponent, computed, watch, nextTick, ref, unref } from 'vue';
  38 + import { defineComponent, computed, watch, ref, unref } from 'vue';
39 39 import PageFooter from './PageFooter.vue';
40   - import { usePageContext } from '/@/hooks/component/usePageContext';
41 40  
42 41 import { useDesign } from '/@/hooks/web/useDesign';
43 42 import { propTypes } from '/@/utils/propTypes';
44 43 import { omit } from 'lodash-es';
45 44 import { PageHeader } from 'ant-design-vue';
46   - import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
47 45 import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
  46 + import { useContentHeight } from './useContentHeight';
  47 + import { WrapperProps } from './types';
48 48  
49 49 export default defineComponent({
50 50 name: 'PageWrapper',
... ... @@ -64,13 +64,26 @@
64 64 fixedHeight: propTypes.bool,
65 65 },
66 66 setup(props, { slots }) {
  67 + const wrapperRef = ref<ElRef>(null);
67 68 const headerRef = ref<ComponentRef>(null);
  69 + const contentRef = ref<ElRef>(null);
68 70 const footerRef = ref<ComponentRef>(null);
69   - const footerHeight = ref(0);
70   - const { prefixCls, prefixVar } = useDesign('page-wrapper');
71   - const { contentHeight, setPageHeight, pageHeight } = usePageContext();
  71 + const { prefixCls } = useDesign('page-wrapper');
72 72 const { footerHeightRef } = useLayoutHeight();
73 73  
  74 + const getProps = computed(() => {
  75 + return props as WrapperProps;
  76 + });
  77 +
  78 + const { redoHeight, contentHeight } = useContentHeight(
  79 + getProps,
  80 + wrapperRef,
  81 + headerRef,
  82 + contentRef,
  83 + footerRef,
  84 + footerHeightRef
  85 + );
  86 +
74 87 const getClass = computed(() => {
75 88 return [
76 89 prefixCls,
... ... @@ -91,7 +104,8 @@
91 104 if (!contentFullHeight) {
92 105 return { ...contentStyle };
93 106 }
94   - const height = `${unref(pageHeight)}px`;
  107 +
  108 + const height = `${unref(contentHeight)}px`;
95 109 return {
96 110 ...contentStyle,
97 111 minHeight: height,
... ... @@ -111,9 +125,9 @@
111 125 });
112 126  
113 127 watch(
114   - () => [contentHeight?.value, getShowFooter.value, footerHeightRef.value],
  128 + () => [getShowFooter.value, footerHeightRef.value],
115 129 () => {
116   - calcContentHeight();
  130 + redoHeight();
117 131 },
118 132 {
119 133 flush: 'post',
... ... @@ -121,91 +135,16 @@
121 135 }
122 136 );
123 137  
124   - onMountedOrActivated(() => {
125   - nextTick(() => {
126   - calcContentHeight();
127   - });
128   - });
129   -
130   - function calcContentHeight() {
131   - if (!props.contentFullHeight) {
132   - return;
133   - }
134   - //fix:in contentHeight mode: delay getting footer and header dom element to get the correct height
135   - const footer = unref(footerRef);
136   - const header = unref(headerRef);
137   - footerHeight.value = 0;
138   - const footerEl = footer?.$el;
139   -
140   - if (footerEl) {
141   - footerHeight.value += footerEl?.offsetHeight ?? 0;
142   - }
143   - let headerHeight = 0;
144   - const headerEl = header?.$el;
145   - if (headerEl) {
146   - headerHeight += headerEl?.offsetHeight ?? 0;
147   - }
148   - // fix:subtract content's marginTop and marginBottom value
149   - let subtractHeight = 0;
150   - const ZERO_PX = '0px';
151   - let marginBottom = ZERO_PX;
152   - let marginTop = ZERO_PX;
153   - const classElments = document.querySelectorAll(`.${prefixVar}-page-wrapper-content`);
154   - if (classElments && classElments.length > 0) {
155   - const contentEl = classElments[0];
156   - const cssStyle = getComputedStyle(contentEl);
157   - marginBottom = cssStyle?.marginBottom ?? ZERO_PX;
158   - marginTop = cssStyle?.marginTop ?? ZERO_PX;
159   - }
160   - if (marginBottom) {
161   - const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));
162   - subtractHeight += contentMarginBottom;
163   - }
164   - if (marginTop) {
165   - const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));
166   - subtractHeight += contentMarginTop;
167   - }
168   -
169   - // fix: wrapper marginTop and marginBottom value
170   - let wrapperSubtractHeight = 0;
171   - let wrapperMarginBottom = ZERO_PX;
172   - let wrapperMarginTop = ZERO_PX;
173   - const wrapperClassElments = document.querySelectorAll(`.${prefixVar}-page-wrapper`);
174   - if (wrapperClassElments && wrapperClassElments.length > 0) {
175   - const contentEl = wrapperClassElments[0];
176   - const cssStyle = getComputedStyle(contentEl);
177   - wrapperMarginBottom = cssStyle?.marginBottom ?? ZERO_PX;
178   - wrapperMarginTop = cssStyle?.marginTop ?? ZERO_PX;
179   - }
180   - if (wrapperMarginBottom) {
181   - const contentMarginBottom = Number(wrapperMarginBottom.replace(/[^\d]/g, ''));
182   - wrapperSubtractHeight += contentMarginBottom;
183   - }
184   - if (wrapperMarginTop) {
185   - const contentMarginTop = Number(wrapperMarginTop.replace(/[^\d]/g, ''));
186   - wrapperSubtractHeight += contentMarginTop;
187   - }
188   - let height =
189   - unref(contentHeight) -
190   - unref(footerHeight) -
191   - headerHeight -
192   - subtractHeight -
193   - wrapperSubtractHeight;
194   - if (unref(getShowFooter)) {
195   - height -= unref(footerHeightRef);
196   - }
197   - setPageHeight?.(height);
198   - }
199   -
200 138 return {
201 139 getContentStyle,
202   - footerRef,
  140 + wrapperRef,
203 141 headerRef,
  142 + contentRef,
  143 + footerRef,
204 144 getClass,
205 145 getHeaderSlots,
206 146 prefixCls,
207 147 getShowFooter,
208   - pageHeight,
209 148 omit,
210 149 getContentClass,
211 150 };
... ...
src/components/Page/src/types.ts 0 → 100644
  1 +import { CSSProperties } from 'vue';
  2 +
  3 +export interface WrapperProps {
  4 + title?: string;
  5 + dense: boolean;
  6 + ghost: boolean;
  7 + content: string;
  8 + contentStyle?: CSSProperties;
  9 + contentBackground: boolean;
  10 + contentFullHeight: boolean;
  11 + contentClass?: string;
  12 + fixedHeight: boolean;
  13 +}
... ...
src/components/Page/src/useContentHeight.ts 0 → 100644
  1 +import { ComputedRef, nextTick, Ref, ref, unref } from 'vue';
  2 +import { WrapperProps } from './types';
  3 +import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
  4 +import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
  5 +import { getViewportOffset } from '/@/utils/domUtils';
  6 +
  7 +export function useContentHeight(
  8 + propsRef: ComputedRef<WrapperProps>,
  9 + wrapperRef: Ref<ElRef>,
  10 + headerRef?: Ref<ComponentRef>,
  11 + contentRef?: Ref<ElRef>,
  12 + footerRef?: Ref<ComponentRef>,
  13 + layoutFooterHeightRef: Ref<number> = ref(0),
  14 + offsetHeightRef: Ref<number> = ref(0)
  15 +) {
  16 + const contentHeight: Ref<Nullable<number>> = ref(null);
  17 +
  18 + const redoHeight = () => {
  19 + nextTick(() => {
  20 + calcContentHeight();
  21 + });
  22 + };
  23 +
  24 + const subtractMargin = (element: HTMLElement | null | undefined): number => {
  25 + let subtractHeight = 0;
  26 + const ZERO_PX = '0px';
  27 + let marginBottom = ZERO_PX;
  28 + let marginTop = ZERO_PX;
  29 + if (element) {
  30 + const cssStyle = getComputedStyle(element);
  31 + marginBottom = cssStyle?.marginBottom ?? ZERO_PX;
  32 + marginTop = cssStyle?.marginTop ?? ZERO_PX;
  33 + }
  34 + if (marginBottom) {
  35 + const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));
  36 + subtractHeight += contentMarginBottom;
  37 + }
  38 + if (marginTop) {
  39 + const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));
  40 + subtractHeight += contentMarginTop;
  41 + }
  42 + return subtractHeight;
  43 + };
  44 +
  45 + const calcContentHeight = async () => {
  46 + const { contentFullHeight } = unref(propsRef);
  47 + if (!contentFullHeight) {
  48 + return;
  49 + }
  50 + // Add a delay to get the correct height
  51 + await nextTick();
  52 +
  53 + const wrapperEl = unref(wrapperRef);
  54 + if (!wrapperEl) {
  55 + return;
  56 + }
  57 + const { bottomIncludeBody } = getViewportOffset(wrapperEl);
  58 + const headerHeight = unref(headerRef)?.$el.offsetHeight ?? 0;
  59 + const footerHeight = unref(footerRef)?.$el.offsetHeight ?? 0;
  60 +
  61 + // content's subtract
  62 + const substractHeight = subtractMargin(unref(contentRef));
  63 + let height =
  64 + bottomIncludeBody -
  65 + unref(layoutFooterHeightRef) -
  66 + unref(offsetHeightRef) -
  67 + headerHeight -
  68 + footerHeight -
  69 + substractHeight;
  70 +
  71 + // fix: compensation height both layout's footer and page's footer was shown
  72 + if (unref(layoutFooterHeightRef) > 0 && footerHeight > 0) {
  73 + height += footerHeight;
  74 + }
  75 +
  76 + contentHeight.value = height;
  77 + };
  78 +
  79 + onMountedOrActivated(() => {
  80 + nextTick(() => {
  81 + calcContentHeight();
  82 + });
  83 + });
  84 + useWindowSizeFn(
  85 + () => {
  86 + calcContentHeight();
  87 + },
  88 + 50,
  89 + { immediate: true }
  90 + );
  91 +
  92 + return { redoHeight, contentHeight };
  93 +}
... ...
src/layouts/default/content/useContentViewHeight.ts
... ... @@ -19,7 +19,7 @@ export function useContentViewHeight() {
19 19 const contentHeight = ref(window.innerHeight);
20 20 const pageHeight = ref(window.innerHeight);
21 21 const getViewHeight = computed(() => {
22   - return unref(contentHeight) - unref(headerHeightRef) || 0;
  22 + return unref(contentHeight) - unref(headerHeightRef) - unref(footerHeightRef) || 0;
23 23 });
24 24  
25 25 useWindowSizeFn(
... ...