Skip to content

Commit

Permalink
fix(table): column resizable for affixed header table (#2606)
Browse files Browse the repository at this point in the history
* fix(table): column resizable

* fix(table): lint error

* test(table): update snapshots
  • Loading branch information
chaishi committed Jul 24, 2023
1 parent 55eb29a commit 63c4b1e
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 182 deletions.
51 changes: 25 additions & 26 deletions src/table/_example/affix.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<!-- 注意组件父元素的宽度 -->
<div class="tdesign-demo-block-column-large tdesign-demo__table tdesign-demo__table-affix" style="width: 100%">
<div class="tdesign-demo-block-column-large tdesign-demo__table tdesign-demo__table-affix" style="width: 830px">
<div>
<t-checkbox v-model="headerAffixedTop">表头吸顶</t-checkbox>
<t-checkbox v-model="footerAffixedBottom" style="margin-left: 32px">表尾吸底</t-checkbox>
Expand All @@ -15,14 +15,10 @@
:columns="columns"
:footData="footData"
:rowClassName="rowClassName"
:pagination="{ defaultCurrent: 1, defaultPageSize: 5, total: TOTAL }"
:headerAffixedTop="headerAffixedTop ? { offsetTop: 87, zIndex: 1000 } : undefined"
:footerAffixedBottom="
footerAffixedBottom ? { offsetBottom: paginationAffixedBottom ? 60 : 0, zIndex: 1000 } : false
"
:horizontalScrollAffixedBottom="
horizontalScrollAffixedBottom ? { offsetBottom: paginationAffixedBottom ? 61 : 0, zIndex: 1000 } : false
"
:pagination="pagination"
:headerAffixedTop="headerAffixedTop ? headerAffixedTopProps : undefined"
:footerAffixedBottom="footerAffixedBottom ? footerAffixedBottomProps : false"
:horizontalScrollAffixedBottom="horizontalScrollAffixedBottom ? horizontalScrollAffixedBottomProps : false"
:paginationAffixedBottom="paginationAffixedBottom"
table-layout="fixed"
dragSort="col"
Expand Down Expand Up @@ -88,9 +84,9 @@ function getColumns(h, { fixedLeftColumn, fixedRightColumn }) {
},
},
{ colKey: 'channel', title: '签署方式', width: '120' },
{ colKey: 'detail.email', title: '邮箱地址', ellipsis: true },
{ colKey: 'matters', title: '申请事项', ellipsis: true },
{ colKey: 'createTime', title: '申请时间' },
{ colKey: 'detail.email', title: '邮箱地址', width: '180' },
{ colKey: 'matters', title: '申请事项', width: '180' },
{ colKey: 'createTime', title: '申请时间', width: '120' },
{
colKey: 'operation',
title: '操作',
Expand Down Expand Up @@ -121,10 +117,27 @@ export default {
// 表尾有一行数据
footData: [{ index: 'footer-row-1', type: '全部类型', description: '-' }],
columns: [],
pagination: { defaultCurrent: 1, defaultPageSize: 5, total: TOTAL },
headerAffixedTopProps: {
offsetTop: 87,
zIndex: 1000,
},
footerAffixedBottomProps: {
offsetBottom: this.paginationAffixedBottom ? 60 : 0,
zIndex: 1000,
},
horizontalScrollAffixedBottomProps: {
offsetBottom: this.paginationAffixedBottom ? 61 : 0,
zIndex: 1000,
},
};
},
watch: {
paginationAffixedBottom(val) {
this.footerAffixedBottomProps.offsetBottom = val ? 60 : 0;
this.horizontalScrollAffixedBottomProps.offsetBottom = val ? 61 : 0;
},
// 底部滚动条 和 Footer 无需同时出现,二选一即可
horizontalScrollAffixedBottom(val) {
val && (this.footerAffixedBottom = false);
Expand Down Expand Up @@ -164,17 +177,3 @@ export default {
},
};
</script>

<style>
/*
* table-layout: auto 模式下,table 元素的宽度设置很重要很重要。
* 如果不设置,列多了之后会挤在一起
* **/
.tdesign-demo__table-affix table {
width: 1200px;
}
.tdesign-demo__table-affix .t-table {
max-width: 800px;
}
</style>
2 changes: 1 addition & 1 deletion src/table/_example/custom-col-button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
}"
:pagination="{ defaultPageSize: 5, defaultCurrent: 1, total: 100 }"
:bordered="bordered"
tableLayout="auto"
drag-sort="col"
stripe
lazyLoad
resizable
@drag-sort="onDragSortChange"
@column-change="onColumnChange"
></t-table>
Expand Down
4 changes: 2 additions & 2 deletions src/table/base-table-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export default {
paginationAffixedBottom: {
type: [Boolean, Object] as PropType<TdBaseTableProps['paginationAffixedBottom']>,
},
/** 是否允许调整列宽。如果想要配置宽度可调整的最小值和最大值,请使用 `column.resize`,示例:`columns: [{ resize: { minWidth: 120, maxWidth: 300 } }]`。<br/> 默认规则:因列宽超出存在横向滚动条时,列宽调整仅影响当前列宽和总列宽;表格列较少没有横向滚动条时,列宽调整表现为自身宽度和相邻宽度变化 */
/** 是否允许调整列宽,设置 `tableLayout=fixed` 效果更友好,此时不允许通过 CSS 设置 `table`元素宽度,也不允许设置 `tableContentWidth`。一般不建议在列宽调整场景使用 `tableLayout: auto`。如果想要配置宽度可调整的最小值和最大值,请使用 `column.resize`,示例:`columns: [{ resize: { minWidth: 120, maxWidth: 300 } }]`。<br/> 默认规则:因列宽超出存在横向滚动条时,列宽调整仅影响当前列宽和总列宽;表格列较少没有横向滚动条时,列宽调整表现为自身宽度和相邻宽度变化 */
resizable: Boolean,
/** HTML 标签 `tr` 的属性。类型为 Function 时,参数说明:`params.row` 表示行数据;`params.rowIndex` 表示行下标;`params.type=body` 表示属性作用于 `tbody` 中的元素;`params.type=foot` 表示属性作用于 `tfoot` 中的元素。<br />示例一:{ draggable: true },<br />示例二:[{ draggable: true }, { title: '超出省略显示' }]。<br /> 示例三:() => [{ draggable: true }] */
rowAttributes: {
Expand Down Expand Up @@ -165,7 +165,7 @@ export default {
type: String,
default: '',
},
/** 表格布局方式 */
/** 表格布局方式,`<table>` 元素原生属性。[MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout)。注意,在列宽调整下场景只能使用 `fixed` 模式 */
tableLayout: {
type: String as PropType<TdBaseTableProps['tableLayout']>,
default: 'fixed' as TdBaseTableProps['tableLayout'],
Expand Down
5 changes: 1 addition & 4 deletions src/table/base-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,7 @@ export default defineComponent({
updateTableAfterColumnResize,
onColumnResizeChange: onInnerResizeChange,
});
const {
resizeLineRef, resizeLineStyle, setEffectColMap, updateTableWidthOnColumnChange,
} = columnResizeParams;
const { resizeLineRef, resizeLineStyle, setEffectColMap } = columnResizeParams;

const dynamicBaseTableClasses = computed(() => [
tableClasses.value,
Expand Down Expand Up @@ -324,7 +322,6 @@ export default defineComponent({
tableBodyRef,
showAffixPagination,
showElement,
updateTableWidthOnColumnChange,
getListener,
renderPagination,
onFixedChange,
Expand Down
15 changes: 2 additions & 13 deletions src/table/hooks/useColumnController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
} from '@vue/composition-api';
import { SettingIcon as TdSettingIcon } from 'tdesign-icons-vue';
import intersection from 'lodash/intersection';
import xorWith from 'lodash/xorWith';
import { CreateElement } from 'vue';
import Checkbox, {
CheckboxGroup,
Expand Down Expand Up @@ -37,13 +36,7 @@ export function getColumnKeys(columns: PrimaryTableCol[], keys = new Set<string>
return keys;
}

export default function useColumnController(
props: TdPrimaryTableProps,
context: SetupContext,
extra?: {
onColumnReduce: (reduceKeys: CheckboxGroupValue) => void;
},
) {
export default function useColumnController(props: TdPrimaryTableProps, context: SetupContext) {
const { classPrefix, global } = useConfig('table');
const { SettingIcon } = useGlobalIcon({ SettingIcon: TdSettingIcon });
const {
Expand Down Expand Up @@ -72,12 +65,8 @@ export default function useColumnController(

const intersectionChecked = computed(() => intersection(columnCheckboxKeys.value, [...enabledColKeys.value]));

watch([displayColumns], ([val], [oldVal]) => {
watch([displayColumns], ([val]) => {
columnCheckboxKeys.value = val || props.defaultDisplayColumns || keys;
if (val.length < oldVal.length) {
const reduceKeys = xorWith(oldVal, val);
extra?.onColumnReduce?.(reduceKeys);
}
});

function getCheckboxOptions(columns: PrimaryTableCol[], arr: CheckboxOptionObj[] = []) {
Expand Down
15 changes: 0 additions & 15 deletions src/table/hooks/useColumnResize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,26 +339,11 @@ export default function useColumnResize(params: {
document.ondragstart = () => false;
};

/**
* 对外暴露函数:更新列数量减少时的表格宽度
* @params colKeys 减少的列
*/
const updateTableWidthOnColumnChange = (colKeys: string[]) => {
const thWidthList = getThWidthList('calculate');
let reduceWidth = 0;
colKeys.forEach((key) => {
reduceWidth += thWidthList[key];
});
const oldTotalWidth = Object.values(thWidthList).reduce((r = 0, n) => r + n);
setTableElmWidth(oldTotalWidth - reduceWidth);
};

return {
resizeLineRef,
resizeLineStyle,
onColumnMouseover,
onColumnMousedown,
setEffectColMap,
updateTableWidthOnColumnChange,
};
}
58 changes: 31 additions & 27 deletions src/table/hooks/useFixed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Ref,
} from '@vue/composition-api';
import get from 'lodash/get';
import xorWith from 'lodash/xorWith';
import debounce from 'lodash/debounce';
import log from '../../_common/js/log';
import { ClassName, Styles } from '../../common';
Expand Down Expand Up @@ -364,14 +365,19 @@ export default function useFixed(
}, 0);
};

const setTableElmWidth = (width: number) => {
if (tableElmWidth.value === width) return;
tableElmWidth.value = width;
};

const updateTableWidth = () => {
const rect = tableContentRef.value?.getBoundingClientRect();
if (!rect) return;
// 存在纵向滚动条,且固定表头时,需去除滚动条宽度
const reduceWidth = isFixedHeader.value ? scrollbarWidth.value : 0;
tableWidth.value = rect.width - reduceWidth - (props.bordered ? 1 : 0);
const elmRect = tableElmRef?.value?.getBoundingClientRect();
tableElmWidth.value = elmRect?.width;
setTableElmWidth(elmRect?.width);
};

const updateAffixPosition = () => {
Expand Down Expand Up @@ -483,28 +489,36 @@ export default function useFixed(

// 影响表头宽度的元素
watch(
[
data,
columns,
bordered,
tableLayout,
fixedRows,
isFixedHeader,
headerAffixedTop,
footerAffixedBottom,
tableContentWidth,
],
[data, bordered, tableLayout, fixedRows, isFixedHeader, headerAffixedTop, footerAffixedBottom, tableContentWidth],
() => {
updateThWidthListHandler();
updateAffixPosition();
const timer = setTimeout(() => {
updateThWidthListHandler();
updateAffixPosition();
clearTimeout(timer);
}, 60);
},
{ immediate: true },
);

watch([finalColumns], ([finalColumns], [preFinalColumns]) => {
const finalColKeys = finalColumns.map((t) => t.colKey);
const preColKeys = preFinalColumns.map((t) => t.colKey);
if (finalColKeys.length < preColKeys.length) {
const reduceKeys = xorWith(preColKeys, finalColKeys);
const thWidthList = getThWidthList('calculate');
let reduceWidth = 0;
reduceKeys.forEach((key) => {
reduceWidth += thWidthList[key];
});
const oldTotalWidth = Object.values(thWidthList).reduce((r = 0, n) => r + n);
setTableElmWidth(oldTotalWidth - reduceWidth);
}
});

const refreshTable = () => {
updateTableWidth();
updateFixedHeader();
// updateTableWidth();
updateThWidthListHandler();
updateFixedHeader();
updateAffixPosition();

if (isFixedColumn.value || isFixedHeader.value) {
Expand All @@ -523,11 +537,10 @@ export default function useFixed(
if (getIEVersion() < 11 || typeof window.ResizeObserver === 'undefined') return;
off(window, 'resize', onResize);
resizeObserver = new window.ResizeObserver(() => {
refreshTable();
const timer = setTimeout(() => {
refreshTable();
clearTimeout(timer);
}, 250);
}, 60);
});
resizeObserver.observe(tableElement);
tableRef.value = tableElement;
Expand All @@ -536,10 +549,6 @@ export default function useFixed(
onMounted(() => {
const scrollWidth = getScrollbarWidthWithCSS();
scrollbarWidth.value = scrollWidth;
const timer = setTimeout(() => {
updateTableWidth();
clearTimeout(timer);
});
const isWatchResize = isFixedColumn.value || isFixedHeader.value || !notNeedThWidthList.value || !data.value.length;
// IE 11 以下使用 window resize;IE 11 以上使用 ResizeObserver
if ((isWatchResize && getIEVersion() < 11) || typeof window.ResizeObserver === 'undefined') {
Expand All @@ -557,11 +566,6 @@ export default function useFixed(
data.value = dataSource;
};

const setTableElmWidth = (width: number) => {
if (tableElmWidth.value === width) return;
tableElmWidth.value = width;
};

const updateTableAfterColumnResize = () => {
updateFixedStatus();
updateFixedHeader();
Expand Down
9 changes: 1 addition & 8 deletions src/table/primary-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import useEditableCell from './hooks/useEditableCell';
import useEditableRow from './hooks/useEditableRow';
import { EditableCellProps } from './editable-cell';
import useStyle from './hooks/useStyle';
import { CheckboxGroupValue } from '..';

export { BASE_TABLE_ALL_EVENTS } from './base-table';

Expand Down Expand Up @@ -70,7 +69,7 @@ export default defineComponent({
} = useClassName();
const { sizeClassNames } = useStyle(props);
// 自定义列配置功能
const { tDisplayColumns, renderColumnController } = useColumnController(props, context, { onColumnReduce });
const { tDisplayColumns, renderColumnController } = useColumnController(props, context);
// 展开/收起行功能
const {
showExpandedRow, showExpandIconColumn, getExpandColumn, renderExpandedRow, onInnerExpandRowClick,
Expand Down Expand Up @@ -149,12 +148,6 @@ export default defineComponent({
setDragSortPrimaryTableRef(primaryTableRef.value);
});

function onColumnReduce(reduceKeys: CheckboxGroupValue) {
if (props.resizable) {
primaryTableRef.value.updateTableWidthOnColumnChange(reduceKeys);
}
}

// 1. 影响列数量的因素有:自定义列配置、展开/收起行、多级表头;2. 影响表头内容的因素有:排序图标、筛选图标
const getColumns = (columns: PrimaryTableCol<TableRowData>[]) => {
const arr: PrimaryTableCol<TableRowData>[] = [];
Expand Down
4 changes: 2 additions & 2 deletions src/table/table.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ loadingProps | Object | - | Typescript:`Partial<LoadingProps>`,[Loading API
maxHeight | String / Number | - | table max height | N
pagination | Object | - | you can use all props of pagination component with paginationProps。Typescript:`PaginationProps`[Pagination API Documents](./pagination?tab=api)[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/table/type.ts) | N
paginationAffixedBottom | Boolean / Object | - | affix props。Typescript:`boolean \| Partial<AffixProps>` | N
resizable | Boolean | false | allow to resize column width | N
resizable | Boolean | false | allow to resize column width, set `tableLayout=fixed` would be better | N
rowAttributes | Object / Array / Function | - | `tr` attributes。Typescript:`TableRowAttributes<T>` `type TableRowAttributes<T> = HTMLElementAttributes \| ((params: { row: T; rowIndex: number; type: 'body' \| 'foot' }) => HTMLElementAttributes) \| Array<TableRowAttributes<T>>`[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts)[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/table/type.ts) | N
rowClassName | String / Object / Array / Function | - | table `th` classname。Typescript:`ClassName \| ((params: RowClassNameParams<T>) => ClassName)` `interface RowClassNameParams<T> { row: T; rowIndex: number; type?: 'body' \| 'foot' }`[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts)[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/table/type.ts) | N
rowKey | String | 'id' | required。unique key for each row data | Y
Expand All @@ -43,7 +43,7 @@ showHeader | Boolean | true | show table header | N
size | String | medium | options: small/medium/large。Typescript:`SizeEnum`[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
stripe | Boolean | false | show stripe style | N
tableContentWidth | String | - | \- | N
tableLayout | String | fixed | table-layout css properties。options: auto/fixed | N
tableLayout | String | fixed | table-layout css properties, [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout). set value to be `fixed` on `resizable=true` please。options: auto/fixed | N
topContent | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
verticalAlign | String | middle | vertical align。options: top/middle/bottom | N
onCellClick | Function | | Typescript:`(context: BaseTableCellEventContext<T>) => void`<br/>trigger on cell clicked。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/table/type.ts)。<br/>`interface BaseTableCellEventContext<T> { row: T; col: BaseTableCol; rowIndex: number; colIndex: number; e: MouseEvent }`<br/> | N
Expand Down
Loading

0 comments on commit 63c4b1e

Please sign in to comment.