Commit 6717fe654e88e6a939a16c523832870388ec1886

Authored by Lan
Committed by GitHub
1 parent ee7c31db

fix: Improve content height calculation (#1136)

* feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。

* feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。 pagewrapper添加 upwardSpace以支持向上递归功能。
src/components/Page/src/PageWrapper.vue
@@ -61,6 +61,7 @@ @@ -61,6 +61,7 @@
61 contentFullHeight: propTypes.bool, 61 contentFullHeight: propTypes.bool,
62 contentClass: propTypes.string, 62 contentClass: propTypes.string,
63 fixedHeight: propTypes.bool, 63 fixedHeight: propTypes.bool,
  64 + upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
64 }, 65 },
65 setup(props, { slots, attrs }) { 66 setup(props, { slots, attrs }) {
66 const wrapperRef = ref(null); 67 const wrapperRef = ref(null);
@@ -78,11 +79,13 @@ @@ -78,11 +79,13 @@
78 return props.contentFullHeight; 79 return props.contentFullHeight;
79 }); 80 });
80 81
  82 + const getUpwardSpace = computed(() => props.upwardSpace);
81 const { redoHeight, setCompensation, contentHeight } = useContentHeight( 83 const { redoHeight, setCompensation, contentHeight } = useContentHeight(
82 getIsContentFullHeight, 84 getIsContentFullHeight,
83 wrapperRef, 85 wrapperRef,
84 [headerRef, footerRef], 86 [headerRef, footerRef],
85 [contentRef], 87 [contentRef],
  88 + getUpwardSpace,
86 ); 89 );
87 setCompensation({ useLayoutFooter: true, elements: [footerRef] }); 90 setCompensation({ useLayoutFooter: true, elements: [footerRef] });
88 91
src/hooks/web/useContentHeight.ts
1 -import { ComputedRef, nextTick, Ref, ref, unref, watch } from 'vue'; 1 +import { ComputedRef, isRef, nextTick, Ref, ref, unref, watch } from 'vue';
2 import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; 2 import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
3 import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; 3 import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
4 import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; 4 import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
5 import { getViewportOffset } from '/@/utils/domUtils'; 5 import { getViewportOffset } from '/@/utils/domUtils';
  6 +import { isNumber, isString } from '/@/utils/is';
6 7
7 export interface CompensationHeight { 8 export interface CompensationHeight {
8 // 使用 layout Footer 高度作为判断补偿高度的条件 9 // 使用 layout Footer 高度作为判断补偿高度的条件
@@ -11,6 +12,8 @@ export interface CompensationHeight { @@ -11,6 +12,8 @@ export interface CompensationHeight {
11 elements?: Ref[]; 12 elements?: Ref[];
12 } 13 }
13 14
  15 +type Upward = number | string | null | undefined;
  16 +
14 /** 17 /**
15 * 动态计算内容高度,根据锚点dom最下坐标到屏幕最下坐标,根据传入dom的高度、padding、margin等值进行动态计算 18 * 动态计算内容高度,根据锚点dom最下坐标到屏幕最下坐标,根据传入dom的高度、padding、margin等值进行动态计算
16 * 最终获取合适的内容高度 19 * 最终获取合适的内容高度
@@ -20,6 +23,7 @@ export interface CompensationHeight { @@ -20,6 +23,7 @@ export interface CompensationHeight {
20 * @param subtractHeightRefs 待减去高度的组件列表 Ref<ElRef | ComponentRef> 23 * @param subtractHeightRefs 待减去高度的组件列表 Ref<ElRef | ComponentRef>
21 * @param substractSpaceRefs 待减去空闲空间(margins/paddings)的组件列表 Ref<ElRef | ComponentRef> 24 * @param substractSpaceRefs 待减去空闲空间(margins/paddings)的组件列表 Ref<ElRef | ComponentRef>
22 * @param offsetHeightRef 计算偏移的响应式高度,计算高度时将直接减去此值 25 * @param offsetHeightRef 计算偏移的响应式高度,计算高度时将直接减去此值
  26 + * @param upwardSpace 向上递归减去空闲空间的 层级 或 直到指定class为止 数值为2代表向上递归两次|数值为ant-layout表示向上递归直到碰见.ant-layout为止
23 * @returns 响应式高度 27 * @returns 响应式高度
24 */ 28 */
25 export function useContentHeight( 29 export function useContentHeight(
@@ -27,6 +31,7 @@ export function useContentHeight( @@ -27,6 +31,7 @@ export function useContentHeight(
27 anchorRef: Ref, 31 anchorRef: Ref,
28 subtractHeightRefs: Ref[], 32 subtractHeightRefs: Ref[],
29 substractSpaceRefs: Ref[], 33 substractSpaceRefs: Ref[],
  34 + upwardSpace: Ref<Upward> | ComputedRef<Upward> | Upward = 0,
30 offsetHeightRef: Ref<number> = ref(0), 35 offsetHeightRef: Ref<number> = ref(0),
31 ) { 36 ) {
32 const contentHeight: Ref<Nullable<number>> = ref(null); 37 const contentHeight: Ref<Nullable<number>> = ref(null);
@@ -45,23 +50,33 @@ export function useContentHeight( @@ -45,23 +50,33 @@ export function useContentHeight(
45 }); 50 });
46 } 51 }
47 52
48 - function calcSubtractSpace(element: HTMLDivElement | null | undefined): number { 53 + function calcSubtractSpace(
  54 + element: Element | null | undefined,
  55 + direction: 'all' | 'top' | 'bottom' = 'all',
  56 + ): number {
  57 + function numberPx(px: string) {
  58 + return Number(px.replace(/[^\d]/g, ''));
  59 + }
49 let subtractHeight = 0; 60 let subtractHeight = 0;
50 const ZERO_PX = '0px'; 61 const ZERO_PX = '0px';
51 - let marginBottom = ZERO_PX;  
52 - let marginTop = ZERO_PX;  
53 if (element) { 62 if (element) {
54 const cssStyle = getComputedStyle(element); 63 const cssStyle = getComputedStyle(element);
55 - marginBottom = cssStyle?.marginBottom ?? ZERO_PX;  
56 - marginTop = cssStyle?.marginTop ?? ZERO_PX;  
57 - }  
58 - if (marginBottom) {  
59 - const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));  
60 - subtractHeight += contentMarginBottom;  
61 - }  
62 - if (marginTop) {  
63 - const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));  
64 - subtractHeight += contentMarginTop; 64 + const marginTop = numberPx(cssStyle?.marginTop ?? ZERO_PX);
  65 + const marginBottom = numberPx(cssStyle?.marginBottom ?? ZERO_PX);
  66 + const paddingTop = numberPx(cssStyle?.paddingTop ?? ZERO_PX);
  67 + const paddingBottom = numberPx(cssStyle?.paddingBottom ?? ZERO_PX);
  68 + if (direction === 'all') {
  69 + subtractHeight += marginTop;
  70 + subtractHeight += marginBottom;
  71 + subtractHeight += paddingTop;
  72 + subtractHeight += paddingBottom;
  73 + } else if (direction === 'top') {
  74 + subtractHeight += marginTop;
  75 + subtractHeight += paddingTop;
  76 + } else {
  77 + subtractHeight += marginBottom;
  78 + subtractHeight += paddingBottom;
  79 + }
65 } 80 }
66 return subtractHeight; 81 return subtractHeight;
67 } 82 }
@@ -80,11 +95,11 @@ export function useContentHeight( @@ -80,11 +95,11 @@ export function useContentHeight(
80 // Add a delay to get the correct height 95 // Add a delay to get the correct height
81 await nextTick(); 96 await nextTick();
82 97
83 - const wrapperEl = getEl(unref(anchorRef));  
84 - if (!wrapperEl) { 98 + const anchorEl = getEl(unref(anchorRef));
  99 + if (!anchorEl) {
85 return; 100 return;
86 } 101 }
87 - const { bottomIncludeBody } = getViewportOffset(wrapperEl); 102 + const { bottomIncludeBody } = getViewportOffset(anchorEl);
88 103
89 // substract elements height 104 // substract elements height
90 let substractHeight = 0; 105 let substractHeight = 0;
@@ -93,17 +108,46 @@ export function useContentHeight( @@ -93,17 +108,46 @@ export function useContentHeight(
93 }); 108 });
94 109
95 // subtract margins / paddings 110 // subtract margins / paddings
96 - let substractSpaceHeight = 0; 111 + let substractSpaceHeight = calcSubtractSpace(anchorEl) ?? 0;
97 substractSpaceRefs.forEach((item) => { 112 substractSpaceRefs.forEach((item) => {
98 substractSpaceHeight += calcSubtractSpace(getEl(unref(item))); 113 substractSpaceHeight += calcSubtractSpace(getEl(unref(item)));
99 }); 114 });
100 115
  116 + // upwardSpace
  117 + let upwardSpaceHeight = 0;
  118 + function upward(element: Element | null, upwardLvlOrClass: number | string | null | undefined) {
  119 + if (element && upwardLvlOrClass) {
  120 + const parent = element.parentElement;
  121 + if (parent) {
  122 + if (isString(upwardLvlOrClass)) {
  123 + if (!parent.classList.contains(upwardLvlOrClass)) {
  124 + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom');
  125 + upward(parent, upwardLvlOrClass);
  126 + } else {
  127 + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom');
  128 + }
  129 + } else if (isNumber(upwardLvlOrClass)) {
  130 + if (upwardLvlOrClass > 0) {
  131 + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom');
  132 + upward(parent, --upwardLvlOrClass);
  133 + }
  134 + }
  135 + }
  136 + }
  137 + }
  138 + if (isRef(upwardSpace)) {
  139 + upward(anchorEl, unref(upwardSpace));
  140 + } else {
  141 + upward(anchorEl, upwardSpace);
  142 + }
  143 +
101 let height = 144 let height =
102 bottomIncludeBody - 145 bottomIncludeBody -
103 unref(layoutFooterHeightRef) - 146 unref(layoutFooterHeightRef) -
104 unref(offsetHeightRef) - 147 unref(offsetHeightRef) -
105 substractHeight - 148 substractHeight -
106 - substractSpaceHeight; 149 + substractSpaceHeight -
  150 + upwardSpaceHeight;
107 151
108 // compensation height 152 // compensation height
109 const calcCompensationHeight = () => { 153 const calcCompensationHeight = () => {