Commit 4d8e39857ea59fff99e69832b4a8cabf3a424c24
Committed by
GitHub
1 parent
c4b22a22
perf(pagewrapper): 优化PageWrapper的高度自适应表现使用getViewportOffset替代useContentViewHeight (#792)
Co-authored-by: NorthLan <lan6995@gmail.com>
Showing
4 changed files
with
135 additions
and
90 deletions
src/components/Page/src/PageWrapper.vue
1 | <template> | 1 | <template> |
2 | - <div :class="getClass"> | 2 | + <div :class="getClass" ref="wrapperRef"> |
3 | <PageHeader | 3 | <PageHeader |
4 | :ghost="ghost" | 4 | :ghost="ghost" |
5 | :title="title" | 5 | :title="title" |
@@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
18 | </template> | 18 | </template> |
19 | </PageHeader> | 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 | <slot></slot> | 22 | <slot></slot> |
23 | </div> | 23 | </div> |
24 | 24 | ||
@@ -35,16 +35,16 @@ | @@ -35,16 +35,16 @@ | ||
35 | <script lang="ts"> | 35 | <script lang="ts"> |
36 | import type { CSSProperties, PropType } from 'vue'; | 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 | import PageFooter from './PageFooter.vue'; | 39 | import PageFooter from './PageFooter.vue'; |
40 | - import { usePageContext } from '/@/hooks/component/usePageContext'; | ||
41 | 40 | ||
42 | import { useDesign } from '/@/hooks/web/useDesign'; | 41 | import { useDesign } from '/@/hooks/web/useDesign'; |
43 | import { propTypes } from '/@/utils/propTypes'; | 42 | import { propTypes } from '/@/utils/propTypes'; |
44 | import { omit } from 'lodash-es'; | 43 | import { omit } from 'lodash-es'; |
45 | import { PageHeader } from 'ant-design-vue'; | 44 | import { PageHeader } from 'ant-design-vue'; |
46 | - import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; | ||
47 | import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; | 45 | import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; |
46 | + import { useContentHeight } from './useContentHeight'; | ||
47 | + import { WrapperProps } from './types'; | ||
48 | 48 | ||
49 | export default defineComponent({ | 49 | export default defineComponent({ |
50 | name: 'PageWrapper', | 50 | name: 'PageWrapper', |
@@ -64,13 +64,26 @@ | @@ -64,13 +64,26 @@ | ||
64 | fixedHeight: propTypes.bool, | 64 | fixedHeight: propTypes.bool, |
65 | }, | 65 | }, |
66 | setup(props, { slots }) { | 66 | setup(props, { slots }) { |
67 | + const wrapperRef = ref<ElRef>(null); | ||
67 | const headerRef = ref<ComponentRef>(null); | 68 | const headerRef = ref<ComponentRef>(null); |
69 | + const contentRef = ref<ElRef>(null); | ||
68 | const footerRef = ref<ComponentRef>(null); | 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 | const { footerHeightRef } = useLayoutHeight(); | 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 | const getClass = computed(() => { | 87 | const getClass = computed(() => { |
75 | return [ | 88 | return [ |
76 | prefixCls, | 89 | prefixCls, |
@@ -91,7 +104,8 @@ | @@ -91,7 +104,8 @@ | ||
91 | if (!contentFullHeight) { | 104 | if (!contentFullHeight) { |
92 | return { ...contentStyle }; | 105 | return { ...contentStyle }; |
93 | } | 106 | } |
94 | - const height = `${unref(pageHeight)}px`; | 107 | + |
108 | + const height = `${unref(contentHeight)}px`; | ||
95 | return { | 109 | return { |
96 | ...contentStyle, | 110 | ...contentStyle, |
97 | minHeight: height, | 111 | minHeight: height, |
@@ -111,9 +125,9 @@ | @@ -111,9 +125,9 @@ | ||
111 | }); | 125 | }); |
112 | 126 | ||
113 | watch( | 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 | flush: 'post', | 133 | flush: 'post', |
@@ -121,91 +135,16 @@ | @@ -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 | return { | 138 | return { |
201 | getContentStyle, | 139 | getContentStyle, |
202 | - footerRef, | 140 | + wrapperRef, |
203 | headerRef, | 141 | headerRef, |
142 | + contentRef, | ||
143 | + footerRef, | ||
204 | getClass, | 144 | getClass, |
205 | getHeaderSlots, | 145 | getHeaderSlots, |
206 | prefixCls, | 146 | prefixCls, |
207 | getShowFooter, | 147 | getShowFooter, |
208 | - pageHeight, | ||
209 | omit, | 148 | omit, |
210 | getContentClass, | 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,7 +19,7 @@ export function useContentViewHeight() { | ||
19 | const contentHeight = ref(window.innerHeight); | 19 | const contentHeight = ref(window.innerHeight); |
20 | const pageHeight = ref(window.innerHeight); | 20 | const pageHeight = ref(window.innerHeight); |
21 | const getViewHeight = computed(() => { | 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 | useWindowSizeFn( | 25 | useWindowSizeFn( |