Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions components/table/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import {
type ComponentObjectPropsOptions,
Fragment,
type PropType,
computed,
defineComponent,
inject,
} from 'vue';
import type { ComponentObjectPropsOptions, PropType } from 'vue';
import { Fragment, computed, defineComponent, inject } from 'vue';
import { isUndefined } from 'lodash-es';
import FCheckbox from '../../checkbox/checkbox.vue';
import { provideKey } from '../const';
import useResize from '../useResize';
Expand Down Expand Up @@ -33,12 +28,17 @@ export default defineComponent({
prefixCls,
sortState,
layout,
rootProps,
} = inject(provideKey);

const { current, onMousedown } = useResize(
props.columns,
layout.widthMap,
handleHeaderResize,
layout.isWatchX,
computed(() => {
return isUndefined(rootProps.height) && rootProps.layout === 'auto';
}),
);

/**
Expand Down Expand Up @@ -144,9 +144,9 @@ export default defineComponent({
<FCheckbox
modelValue={isAllSelected.value}
indeterminate={
!isAllSelected.value
&& isCurrentDataAnySelected.value
}
!isAllSelected.value
&& isCurrentDataAnySelected.value
}
onChange={handleSelectAll}
/>
</div>
Expand Down
14 changes: 5 additions & 9 deletions components/table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ export default defineComponent({
clearSelect,
wrapperRef,
wrapperClass,
layout,
columns,
rootProps,
toggleRowExpend,
Expand Down Expand Up @@ -188,23 +187,20 @@ export default defineComponent({
);

const render = () => {
if (!layout.initRef.value) {
return;
}
return (
<>
{composed.value && rootProps.showHeader && (
<HeaderTable columns={columns.value} />
)}
{rootProps.virtualScroll && showData.value.length
? (
<VirtualTable columns={columns.value} />
<VirtualTable columns={columns.value} />
)
: (
<BodyTable
composed={composed.value}
columns={columns.value}
/>
<BodyTable
composed={composed.value}
columns={columns.value}
/>
)}
{showData.value.length === 0 && <NoData></NoData>}
</>
Expand Down
52 changes: 28 additions & 24 deletions components/table/useResize.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Ref, ref } from 'vue';
import type { ComputedRef, Ref } from 'vue';
import { ref } from 'vue';
import { cloneDeep } from 'lodash-es';
import { useEventListener } from '@vueuse/core';
import { depx } from '../_util/utils';
Expand All @@ -16,6 +17,8 @@ export default (
columns: ColumnInst[],
widthMap: Ref<Record<string, WidthItem>>,
handleHeaderResize: ReturnType<typeof useTableEvent>['handleHeaderResize'],
isWatchX: Ref<boolean>,
isWidthAuto: ComputedRef<boolean>,
) => {
const current = ref<{
id: number;
Expand All @@ -24,6 +27,8 @@ export default (
width: number;
}>(null);

let _widthMap: Record<string, WidthItem> = null;

const onMousedown = (
column: ColumnInst,
columnIndex: number,
Expand All @@ -37,36 +42,33 @@ export default (
(event.target as HTMLElement).parentElement.offsetWidth,
),
};
_widthMap = cloneDeep(widthMap.value);
isWatchX.value = false;
};

const onMousemove = (event: MouseEvent) => {
if (!current.value) {
return;
}
const _widthMap = cloneDeep(widthMap.value);
const leftColumns = columns
.slice(0, current.value.columnIndex)
.filter((col) => {
return !_widthMap[col.id].width;
});
const rightColumns = columns
.slice(current.value.columnIndex + 1)
.filter((col) => {
return !_widthMap[col.id].width;
if (!_widthMap) {
return;
}
const currentClientX = event.clientX;
const offset = currentClientX - current.value.clientX;

if (!isWidthAuto.value) {
const rightColumns = columns.slice(current.value.columnIndex + 1);
widthMap.value[current.value.id].width = offset + _widthMap[current.value.id].width;
rightColumns.forEach((col) => {
widthMap.value[col.id].width = (-offset / rightColumns.length) + _widthMap[col.id].width;
});
const offsetX
= ((event.clientX - current.value.clientX)
* (leftColumns.length + rightColumns.length))
/ rightColumns.length;
const width = current.value.width + offsetX;
const currentColumn = columns[current.value.columnIndex];
if (
currentColumn.props.minWidth
&& width >= currentColumn.props.minWidth
) {
_widthMap[current.value.id].width = width;
_widthMap[current.value.id].minWidth = width;
widthMap.value = _widthMap;
} else {
widthMap.value[current.value.id] = {
..._widthMap[current.value.id],
width: offset + current.value.width,
minWidth: offset + current.value.width,
maxWidth: offset + current.value.width,
};
}
};

Expand Down Expand Up @@ -104,6 +106,8 @@ export default (

// reset current
current.value = null;
_widthMap = null;
isWatchX.value = true;
};

useEventListener(window.document, 'mousemove', onMousemove);
Expand Down
151 changes: 112 additions & 39 deletions components/table/useTableLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export interface WidthItem {
width?: number;
minWidth?: number;
maxWidth?: number;
origin?: {
width?: number;
minWidth?: number;
maxWidth?: number;
};
}

/**
Expand Down Expand Up @@ -46,7 +51,6 @@ export default function useTableLayout({
const isScrollX = ref(false);
const isScrollY = ref(false);
const bodyHeight = ref(0);
const initRef = ref(false);

// 兼容 windows 浏览器滚动条导致高度有小数的场景
const propHeight = computed(() => Math.floor(props.height));
Expand All @@ -55,7 +59,9 @@ export default function useTableLayout({
return isUndefined(props.height) && props.layout === 'auto';
});

const min = 80;
const isWatchX = ref(true);

const min = 100;

const computeY = () => {
// 第一次渲染时会出现 bodyWrapperHeight = 0,必须再nextTick
Expand Down Expand Up @@ -89,11 +95,35 @@ export default function useTableLayout({
};

const computeX = () => {
if (!isWatchX.value) {
return;
}
const $wrapper = wrapperRef.value;
if (!$wrapper) {
return;
}

if (isWidthAuto.value) {
columns.value.forEach((column) => {
const widthObj: WidthItem = {
id: column.id,
};
const width = column.props.width;
const minWidth = column.props.minWidth;
if (width) {
widthObj.width = width;
} else if (minWidth) {
widthObj.minWidth = minWidth;
} else if (
column.props.type === 'selection'
|| column.props.type === 'expand'
) {
widthObj.minWidth = min;
}
if (!isEqual(widthMap.value[column.id], widthObj)) {
widthMap.value[column.id] = widthObj;
}
});
const $bodyTable = bodyTableRef.value;
if (!$bodyTable) {
return;
Expand All @@ -106,50 +136,94 @@ export default function useTableLayout({
: _wrapperWidth;
let bodyMinWidth = 0;

Object.keys(widthMap.value).forEach((id) => {
const widthObj = widthMap.value[id];
bodyMinWidth += widthObj.width ?? widthObj.minWidth ?? min;
const newWidthList: Record<string, WidthItem> = {};
columns.value.forEach((column) => {
const widthObj: WidthItem = {
id: column.id,
origin: {},
};
const width = column.props.width;
const minWidth = column.props.minWidth;
if (width || minWidth) {
// 用户设置的宽度优先级最高
widthObj.origin = {
minWidth,
width,
};
} else if (
column.props.type === 'selection'
|| column.props.type === 'expand'
) {
widthObj.origin = {
width: min,
};
} else {
widthObj.origin = {
minWidth: min,
};
}
newWidthList[column.id] = widthObj;
});

Object.values(newWidthList).forEach((widthObj) => {
bodyMinWidth += widthObj.origin.width ?? widthObj.origin.minWidth ?? min;
});

if (bodyMinWidth < wrapperWidth) {
isScrollX.value = false;
bodyWidth.value = wrapperWidth;
const additionalWidth = wrapperWidth - bodyMinWidth;
const hasMinItems = Object.values(newWidthList).filter((item) => !item.origin.width);
const hasWidthItems = Object.values(newWidthList).filter((item) => item.origin.width);
let addedWidth = 0;
hasMinItems.forEach((item, index) => {
const origin = newWidthList[item.id].origin;
if (index !== hasMinItems.length - 1) {
const widthObj = {
id: item.id,
width: origin.minWidth + Math.ceil(additionalWidth / hasMinItems.length),
};
if (!isEqual(widthObj, widthMap.value[item.id])) {
widthMap.value[item.id] = widthObj;
}
addedWidth += Math.ceil(additionalWidth / hasMinItems.length);
} else {
const widthObj = {
id: item.id,
width: origin.minWidth + additionalWidth - addedWidth,
};
if (!isEqual(widthObj, widthMap.value[item.id])) {
widthMap.value[item.id] = widthObj;
}
}
});
hasWidthItems.forEach((item) => {
const origin = newWidthList[item.id].origin;
const widthObj = {
id: item.id,
width: origin.width,
};
if (!isEqual(widthObj, widthMap.value[item.id])) {
widthMap.value[item.id] = widthObj;
}
});
} else {
isScrollX.value = true;
bodyWidth.value = bodyMinWidth;
columns.value.forEach((column) => {
const origin = newWidthList[column.id].origin;
const widthObj = {
id: column.id,
width: origin.width ?? origin.minWidth,
};
if (!isEqual(widthObj, widthMap.value[column.id])) {
widthMap.value[column.id] = widthObj;
}
});
}
}
};

const computeColumnWidth = () => {
const newWidthList: Record<string, WidthItem> = {};
columns.value.forEach((column) => {
const widthObj: WidthItem = {
id: column.id,
};
const width = column.props.width;
const minWidth = column.props.minWidth;
if (width || minWidth) {
// 用户设置的宽度优先级最高
widthObj.width = width;
widthObj.minWidth = minWidth;
} else if (
column.props.type === 'selection'
|| column.props.type === 'expand'
) {
widthObj.width = min;
}
newWidthList[column.id] = widthObj;
});
// 如果值一样则没必要再次渲染,可减少一次多余渲染
if (!isEqual(newWidthList, widthMap.value)) {
widthMap.value = newWidthList;
}
nextTick(() => {
initRef.value = true;
});
};

const watchResizeDisableRef = ref(false);

onDeactivated(() => {
Expand All @@ -176,10 +250,9 @@ export default function useTableLayout({
return watchResizeDisableRef.value || !isWidthAuto.value;
}));

// 根据列数据,计算列宽度
watch([columns, wrapperRef], computeColumnWidth);

watch([widthMap, wrapperRef, () => props.bordered], computeX);
watch([columns, wrapperRef, () => props.bordered, isWidthAuto], () => {
computeX();
});

watch(
[
Expand Down Expand Up @@ -211,6 +284,6 @@ export default function useTableLayout({
bodyHeight,
isScrollX,
isScrollY,
initRef,
isWatchX,
};
}
Loading