Commit 6717fe654e88e6a939a16c523832870388ec1886
Committed by
GitHub
1 parent
ee7c31db
fix: Improve content height calculation (#1136)
* feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。 * feat(useContentHeight): 为useContentHeight 添加 向上递归 移除差值 的功能。 pagewrapper添加 upwardSpace以支持向上递归功能。
Showing
2 changed files
with
66 additions
and
19 deletions
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 = () => { |