Commit dd158a17fe1c512a333fe19f0665d35bf5bac93e
Committed by
GitHub
1 parent
c8d59a0b
feat: 添加table继承父元素高度的功能 (#1523)
在保证了原有的高度计算上,额外新增继承父级高度, 只需设置isCanResizeParent:true
Showing
8 changed files
with
140 additions
and
11 deletions
src/components/Table/src/BasicTable.vue
1 | <template> | 1 | <template> |
2 | <div ref="wrapRef" :class="getWrapperClass"> | 2 | <div ref="wrapRef" :class="getWrapperClass"> |
3 | <BasicForm | 3 | <BasicForm |
4 | + ref="formRef" | ||
4 | submitOnReset | 5 | submitOnReset |
5 | v-bind="getFormProps" | 6 | v-bind="getFormProps" |
6 | v-if="getBindValues.useSearchForm" | 7 | v-if="getBindValues.useSearchForm" |
@@ -25,7 +26,7 @@ | @@ -25,7 +26,7 @@ | ||
25 | <slot :name="item" v-bind="data || {}"></slot> | 26 | <slot :name="item" v-bind="data || {}"></slot> |
26 | </template> | 27 | </template> |
27 | 28 | ||
28 | - <template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex"> | 29 | + <template #[`header-${column.dataIndex}`] v-for="(column, index) in columns" :key="index"> |
29 | <HeaderCell :column="column" /> | 30 | <HeaderCell :column="column" /> |
30 | </template> | 31 | </template> |
31 | </Table> | 32 | </Table> |
@@ -97,6 +98,7 @@ | @@ -97,6 +98,7 @@ | ||
97 | const tableData = ref<Recordable[]>([]); | 98 | const tableData = ref<Recordable[]>([]); |
98 | 99 | ||
99 | const wrapRef = ref(null); | 100 | const wrapRef = ref(null); |
101 | + const formRef = ref(null); | ||
100 | const innerPropsRef = ref<Partial<BasicTableProps>>(); | 102 | const innerPropsRef = ref<Partial<BasicTableProps>>(); |
101 | 103 | ||
102 | const { prefixCls } = useDesign('basic-table'); | 104 | const { prefixCls } = useDesign('basic-table'); |
@@ -185,6 +187,8 @@ | @@ -185,6 +187,8 @@ | ||
185 | getColumnsRef, | 187 | getColumnsRef, |
186 | getRowSelectionRef, | 188 | getRowSelectionRef, |
187 | getDataSourceRef, | 189 | getDataSourceRef, |
190 | + wrapRef, | ||
191 | + formRef, | ||
188 | ); | 192 | ); |
189 | 193 | ||
190 | const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef); | 194 | const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef); |
@@ -318,6 +322,7 @@ | @@ -318,6 +322,7 @@ | ||
318 | emit('register', tableAction, formActions); | 322 | emit('register', tableAction, formActions); |
319 | 323 | ||
320 | return { | 324 | return { |
325 | + formRef, | ||
321 | tableElRef, | 326 | tableElRef, |
322 | getBindValues, | 327 | getBindValues, |
323 | getLoading, | 328 | getLoading, |
@@ -352,6 +357,7 @@ | @@ -352,6 +357,7 @@ | ||
352 | 357 | ||
353 | .@{prefix-cls} { | 358 | .@{prefix-cls} { |
354 | max-width: 100%; | 359 | max-width: 100%; |
360 | + height: 100%; | ||
355 | 361 | ||
356 | &-row__striped { | 362 | &-row__striped { |
357 | td { | 363 | td { |
src/components/Table/src/hooks/useTableScroll.ts
1 | import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table'; | 1 | import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table'; |
2 | -import type { Ref, ComputedRef } from 'vue'; | 2 | +import { Ref, ComputedRef, ref } from 'vue'; |
3 | import { computed, unref, nextTick, watch } from 'vue'; | 3 | import { computed, unref, nextTick, watch } from 'vue'; |
4 | import { getViewportOffset } from '/@/utils/domUtils'; | 4 | import { getViewportOffset } from '/@/utils/domUtils'; |
5 | import { isBoolean } from '/@/utils/is'; | 5 | import { isBoolean } from '/@/utils/is'; |
@@ -14,7 +14,10 @@ export function useTableScroll( | @@ -14,7 +14,10 @@ export function useTableScroll( | ||
14 | columnsRef: ComputedRef<BasicColumn[]>, | 14 | columnsRef: ComputedRef<BasicColumn[]>, |
15 | rowSelectionRef: ComputedRef<TableRowSelection | null>, | 15 | rowSelectionRef: ComputedRef<TableRowSelection | null>, |
16 | getDataSourceRef: ComputedRef<Recordable[]>, | 16 | getDataSourceRef: ComputedRef<Recordable[]>, |
17 | + wrapRef: Ref<HTMLElement | null>, | ||
18 | + formRef: Ref<ComponentRef>, | ||
17 | ) { | 19 | ) { |
20 | + const tableHeightRef: Ref<Nullable<number | string>> = ref(167); | ||
18 | const modalFn = useModalContext(); | 21 | const modalFn = useModalContext(); |
19 | 22 | ||
20 | // Greater than animation time 280 | 23 | // Greater than animation time 280 |
@@ -41,7 +44,8 @@ export function useTableScroll( | @@ -41,7 +44,8 @@ export function useTableScroll( | ||
41 | }); | 44 | }); |
42 | } | 45 | } |
43 | 46 | ||
44 | - function setHeight() { | 47 | + function setHeight(height: number) { |
48 | + tableHeightRef.value = height; | ||
45 | // Solve the problem of modal adaptive height calculation when the form is placed in the modal | 49 | // Solve the problem of modal adaptive height calculation when the form is placed in the modal |
46 | modalFn?.redoModalHeight?.(); | 50 | modalFn?.redoModalHeight?.(); |
47 | } | 51 | } |
@@ -52,7 +56,8 @@ export function useTableScroll( | @@ -52,7 +56,8 @@ export function useTableScroll( | ||
52 | let bodyEl: HTMLElement | null; | 56 | let bodyEl: HTMLElement | null; |
53 | 57 | ||
54 | async function calcTableHeight() { | 58 | async function calcTableHeight() { |
55 | - const { resizeHeightOffset, pagination, maxHeight } = unref(propsRef); | 59 | + const { resizeHeightOffset, pagination, maxHeight, isCanResizeParent, useSearchForm } = |
60 | + unref(propsRef); | ||
56 | const tableData = unref(getDataSourceRef); | 61 | const tableData = unref(getDataSourceRef); |
57 | 62 | ||
58 | const table = unref(tableElRef); | 63 | const table = unref(tableElRef); |
@@ -94,11 +99,8 @@ export function useTableScroll( | @@ -94,11 +99,8 @@ export function useTableScroll( | ||
94 | 99 | ||
95 | if (!headEl) return; | 100 | if (!headEl) return; |
96 | 101 | ||
97 | - // Table height from bottom | ||
98 | - const { bottomIncludeBody } = getViewportOffset(headEl); | ||
99 | // Table height from bottom height-custom offset | 102 | // Table height from bottom height-custom offset |
100 | - | ||
101 | - const paddingHeight = 32; | 103 | + let paddingHeight = 32; |
102 | // Pager height | 104 | // Pager height |
103 | let paginationHeight = 2; | 105 | let paginationHeight = 2; |
104 | if (!isBoolean(pagination)) { | 106 | if (!isBoolean(pagination)) { |
@@ -129,6 +131,35 @@ export function useTableScroll( | @@ -129,6 +131,35 @@ export function useTableScroll( | ||
129 | headerHeight = (headEl as HTMLElement).offsetHeight; | 131 | headerHeight = (headEl as HTMLElement).offsetHeight; |
130 | } | 132 | } |
131 | 133 | ||
134 | + let bottomIncludeBody = 0; | ||
135 | + if (unref(wrapRef) && isCanResizeParent) { | ||
136 | + const tablePadding = 12; | ||
137 | + const formMargin = 16; | ||
138 | + let paginationMargin = 10; | ||
139 | + const wrapHeight = unref(wrapRef)?.offsetHeight ?? 0; | ||
140 | + | ||
141 | + let formHeight = unref(formRef)?.$el.offsetHeight ?? 0; | ||
142 | + if (formHeight) { | ||
143 | + formHeight += formMargin; | ||
144 | + } | ||
145 | + if (isBoolean(pagination) && !pagination) { | ||
146 | + paginationMargin = 0; | ||
147 | + } | ||
148 | + if (isBoolean(useSearchForm) && !useSearchForm) { | ||
149 | + paddingHeight = 0; | ||
150 | + } | ||
151 | + | ||
152 | + const headerCellHeight = | ||
153 | + (tableEl.querySelector('.ant-table-title') as HTMLElement)?.offsetHeight ?? 0; | ||
154 | + | ||
155 | + console.log(wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin); | ||
156 | + bottomIncludeBody = | ||
157 | + wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin; | ||
158 | + } else { | ||
159 | + // Table height from bottom | ||
160 | + bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody; | ||
161 | + } | ||
162 | + | ||
132 | let height = | 163 | let height = |
133 | bottomIncludeBody - | 164 | bottomIncludeBody - |
134 | (resizeHeightOffset || 0) - | 165 | (resizeHeightOffset || 0) - |
@@ -136,9 +167,8 @@ export function useTableScroll( | @@ -136,9 +167,8 @@ export function useTableScroll( | ||
136 | paginationHeight - | 167 | paginationHeight - |
137 | footerHeight - | 168 | footerHeight - |
138 | headerHeight; | 169 | headerHeight; |
139 | - | ||
140 | height = (height > maxHeight! ? (maxHeight as number) : height) ?? height; | 170 | height = (height > maxHeight! ? (maxHeight as number) : height) ?? height; |
141 | - setHeight(); | 171 | + setHeight(height); |
142 | 172 | ||
143 | bodyEl!.style.height = `${height}px`; | 173 | bodyEl!.style.height = `${height}px`; |
144 | } | 174 | } |
@@ -176,10 +206,11 @@ export function useTableScroll( | @@ -176,10 +206,11 @@ export function useTableScroll( | ||
176 | }); | 206 | }); |
177 | 207 | ||
178 | const getScrollRef = computed(() => { | 208 | const getScrollRef = computed(() => { |
209 | + const tableHeight = unref(tableHeightRef); | ||
179 | const { canResize, scroll } = unref(propsRef); | 210 | const { canResize, scroll } = unref(propsRef); |
180 | return { | 211 | return { |
181 | x: unref(getScrollX), | 212 | x: unref(getScrollX), |
182 | - y: canResize ? '100%' : null, | 213 | + y: canResize ? tableHeight : null, |
183 | scrollToFirstRowOnChange: false, | 214 | scrollToFirstRowOnChange: false, |
184 | ...scroll, | 215 | ...scroll, |
185 | }; | 216 | }; |
src/components/Table/src/props.ts
@@ -97,6 +97,7 @@ export const basicProps = { | @@ -97,6 +97,7 @@ export const basicProps = { | ||
97 | default: null, | 97 | default: null, |
98 | }, | 98 | }, |
99 | ellipsis: { type: Boolean, default: true }, | 99 | ellipsis: { type: Boolean, default: true }, |
100 | + isCanResizeParent: { type: Boolean, default: false }, | ||
100 | canResize: { type: Boolean, default: true }, | 101 | canResize: { type: Boolean, default: true }, |
101 | clearSelectOnPageChange: propTypes.bool, | 102 | clearSelectOnPageChange: propTypes.bool, |
102 | resizeHeightOffset: propTypes.number.def(0), | 103 | resizeHeightOffset: propTypes.number.def(0), |
src/components/Table/src/types/table.ts
@@ -191,6 +191,8 @@ export interface BasicTableProps<T = any> { | @@ -191,6 +191,8 @@ export interface BasicTableProps<T = any> { | ||
191 | actionColumn?: BasicColumn; | 191 | actionColumn?: BasicColumn; |
192 | // 文本超过宽度是否显示。。。 | 192 | // 文本超过宽度是否显示。。。 |
193 | ellipsis?: boolean; | 193 | ellipsis?: boolean; |
194 | + // 是否继承父级高度(父级高度-表单高度-padding高度) | ||
195 | + isCanResizeParent?: boolean; | ||
194 | // 是否可以自适应高度 | 196 | // 是否可以自适应高度 |
195 | canResize?: boolean; | 197 | canResize?: boolean; |
196 | // 自适应高度偏移, 计算结果-偏移量 | 198 | // 自适应高度偏移, 计算结果-偏移量 |
src/locales/lang/en/routes/demo.ts
@@ -195,5 +195,6 @@ export default { | @@ -195,5 +195,6 @@ export default { | ||
195 | editCellTable: 'Editable cell', | 195 | editCellTable: 'Editable cell', |
196 | editRowTable: 'Editable row', | 196 | editRowTable: 'Editable row', |
197 | authColumn: 'Auth column', | 197 | authColumn: 'Auth column', |
198 | + resizeParentHeightTable: 'resizeParentHeightTable', | ||
198 | }, | 199 | }, |
199 | }; | 200 | }; |
src/locales/lang/zh-CN/routes/demo.ts
src/router/routes/modules/demo/comp.ts
@@ -239,6 +239,14 @@ const comp: AppRouteModule = { | @@ -239,6 +239,14 @@ const comp: AppRouteModule = { | ||
239 | title: t('routes.demo.table.authColumn'), | 239 | title: t('routes.demo.table.authColumn'), |
240 | }, | 240 | }, |
241 | }, | 241 | }, |
242 | + { | ||
243 | + path: 'resizeParentHeightTable', | ||
244 | + name: 'ResizeParentHeightTable', | ||
245 | + component: () => import('/@/views/demo/table/ResizeParentHeightTable.vue'), | ||
246 | + meta: { | ||
247 | + title: t('routes.demo.table.resizeParentHeightTable'), | ||
248 | + }, | ||
249 | + }, | ||
242 | ], | 250 | ], |
243 | }, | 251 | }, |
244 | { | 252 | { |
src/views/demo/table/ResizeParentHeightTable.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="h-full flex p-4"> | ||
3 | + <div class="flex flex-col pr-4 w-1/2"> | ||
4 | + <div class="flex-1"> | ||
5 | + <BasicTable @register="registerTable" /> | ||
6 | + </div> | ||
7 | + <div class="h-4"></div> | ||
8 | + <div class="flex-1"> | ||
9 | + <BasicTable @register="registerTable" /> | ||
10 | + </div> | ||
11 | + </div> | ||
12 | + <div class="flex-1 flex flex-col w-1/2 h-full"> | ||
13 | + <div class="h-1/3 mb-4"> | ||
14 | + <BasicTable @register="registerTable" /> | ||
15 | + </div> | ||
16 | + <div class="h-1/3 mb-4"> | ||
17 | + <BasicTable @register="registerTable2" /> | ||
18 | + </div> | ||
19 | + <div class="h-1/3"> | ||
20 | + <BasicTable @register="registerTable1" /> | ||
21 | + </div> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | +</template> | ||
25 | +<script lang="ts"> | ||
26 | + import { defineComponent } from 'vue'; | ||
27 | + import { BasicTable, useTable } from '/@/components/Table'; | ||
28 | + import { getBasicColumns, getFormConfig } from './tableData'; | ||
29 | + | ||
30 | + import { demoListApi } from '/@/api/demo/table'; | ||
31 | + | ||
32 | + export default defineComponent({ | ||
33 | + components: { BasicTable }, | ||
34 | + setup(_) { | ||
35 | + const [registerTable] = useTable({ | ||
36 | + api: demoListApi, | ||
37 | + columns: getBasicColumns(), | ||
38 | + useSearchForm: false, | ||
39 | + formConfig: getFormConfig(), | ||
40 | + showTableSetting: false, | ||
41 | + tableSetting: { fullScreen: true }, | ||
42 | + showIndexColumn: false, | ||
43 | + isCanResizeParent: true, | ||
44 | + rowKey: 'id', | ||
45 | + }); | ||
46 | + | ||
47 | + const [registerTable1] = useTable({ | ||
48 | + api: demoListApi, | ||
49 | + columns: getBasicColumns(), | ||
50 | + formConfig: getFormConfig(), | ||
51 | + showTableSetting: false, | ||
52 | + tableSetting: { fullScreen: true }, | ||
53 | + showIndexColumn: false, | ||
54 | + isCanResizeParent: true, | ||
55 | + useSearchForm: false, | ||
56 | + rowKey: 'id', | ||
57 | + }); | ||
58 | + | ||
59 | + const [registerTable2] = useTable({ | ||
60 | + api: demoListApi, | ||
61 | + columns: getBasicColumns(), | ||
62 | + formConfig: getFormConfig(), | ||
63 | + showTableSetting: false, | ||
64 | + tableSetting: { fullScreen: true }, | ||
65 | + showIndexColumn: false, | ||
66 | + isCanResizeParent: true, | ||
67 | + useSearchForm: false, | ||
68 | + pagination: false, | ||
69 | + rowKey: 'id', | ||
70 | + }); | ||
71 | + | ||
72 | + return { | ||
73 | + registerTable, | ||
74 | + registerTable1, | ||
75 | + registerTable2, | ||
76 | + }; | ||
77 | + }, | ||
78 | + }); | ||
79 | +</script> |