Skip to content

Commit

Permalink
Merge pull request #757 from tinna3445/develop
Browse files Browse the repository at this point in the history
feat(base-table): 支持表格列可以拖拽宽度
  • Loading branch information
chaishi authored Apr 27, 2022
2 parents 141efed + 9dc0e6c commit c1e5133
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/_common
1 change: 1 addition & 0 deletions src/table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- hooks/useAsyncLoading 异步加载功能,PrimaryTable
- hooks/useClassName 全部类名,BaseTable
- hooks/useColumnController 自定义列配置,PrimaryTable
- hooks/useColumnResize 列宽可拖动,BaseTable
- hooks/useFilter 过滤/筛选,PrimaryTable
- hooks/useFixed 固定表头/固定列/固定行,BaseTable
- hooks/useMultiHeader 多级表头,BaseTable
Expand Down
12 changes: 11 additions & 1 deletion src/table/base-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import pick from 'lodash/pick';
import props from './base-table-props';
import useTableHeader from './hooks/useTableHeader';
import useColumnResize from './hooks/useColumnResize';
import useFixed from './hooks/useFixed';
import usePagination from './hooks/usePagination';
import useVirtualScroll from '../hooks/useVirtualScroll';
Expand Down Expand Up @@ -72,6 +73,10 @@ export default defineComponent({
const { isMultipleHeader, spansAndLeafNodes, thList } = useTableHeader(props);
const { dataSource, isPaginateData, renderPagination } = usePagination(props, context);

// 列宽拖拽逻辑
const columnResizeParams = useColumnResize(tableElmRef);
const { resizeLineRef, resizeLineStyle } = columnResizeParams;

const dynamicBaseTableClasses = computed(() => [
tableClasses.value,
{
Expand Down Expand Up @@ -200,6 +205,9 @@ export default defineComponent({
updateHeaderScroll,
onInnerScroll,
refreshTable,
resizeLineRef,
resizeLineStyle,
columnResizeParams,
};
},

Expand Down Expand Up @@ -232,6 +240,7 @@ export default defineComponent({
spansAndLeafNodes={this.spansAndLeafNodes}
thList={this.thList}
thWidthList={this.thWidthList}
columnResizeParams={this.columnResizeParams}
/>
</table>
</div>
Expand Down Expand Up @@ -274,8 +283,8 @@ export default defineComponent({
style={this.tableContentStyles}
onScroll={this.onInnerScroll}
>
<div ref="resizeLineRef" class={this.tableBaseClass.resizeLine} style={this.resizeLineStyle}></div>
{this.isVirtual && <div class={this.virtualScrollClasses.cursor} style={virtualStyle} />}

<table ref="tableElmRef" class={this.tableElmClasses} style={this.tableElementStyles}>
{colgroup}
<THead
Expand All @@ -286,6 +295,7 @@ export default defineComponent({
bordered={this.bordered}
spansAndLeafNodes={this.spansAndLeafNodes}
thList={this.thList}
columnResizeParams={this.columnResizeParams}
/>
<TBody scopedSlots={this.$scopedSlots} props={tableBodyProps} on={on} />
<TFoot
Expand Down
2 changes: 2 additions & 0 deletions src/table/hooks/useClassName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export default function useClassName() {
scrollbarDivider: `${classPrefix.value}-table__scroll-bar-divider`,
// 当用户设置 height 为固定高度,为保证行元素铺满 table,则需设置 table 元素高度为 100%
fullHeight: `${classPrefix.value}-table--full-height`,
// 拖拽列时的标记线
resizeLine: `${classPrefix.value}-table__resize-line`,
},

tdAlignClasses: {
Expand Down
107 changes: 107 additions & 0 deletions src/table/hooks/useColumnResize.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { ref, reactive } from '@vue/composition-api';
import { TableColumns } from './useMultiHeader';

export default function useColumnResize(tableElmRef: any) {
const resizeLineRef = ref<HTMLDivElement>();

const resizeLineParams = {
isDragging: false,
draggingCol: null as HTMLElement,
draggingStart: 0,
};

const resizeLineStyle = reactive({
display: 'none',
left: '10px',
height: '10px',
});

// 表格列宽拖拽事件
// 只在表头显示拖拽图标
const onColumnMouseover = (e: MouseEvent) => {
if (!resizeLineRef.value) return;

const target = e.target as HTMLElement;
const targetBoundRect = target.getBoundingClientRect();
if (!resizeLineParams.isDragging) {
// 最小宽度暂定为30,如果单元格小于30,则不能拖拽
// 当离右边框的距离不超过8时,显示拖拽图标
if (targetBoundRect.width > 30 && targetBoundRect.right - e.pageX <= 8) {
target.style.cursor = 'col-resize';
resizeLineParams.draggingCol = target;
} else {
target.style.cursor = '';
resizeLineParams.draggingCol = null;
}
}
};

// 调整表格列宽
const onColumnMousedown = (e: MouseEvent, col: TableColumns[0]) => {
// 非resize的点击,不做处理
if (!resizeLineParams.draggingCol) return;

const target = e.target as HTMLElement;
const targetBoundRect = target.getBoundingClientRect();
const tableBoundRect = tableElmRef.value?.getBoundingClientRect();
const resizeLinePos = targetBoundRect.right - tableBoundRect.left;
const colLeft = targetBoundRect.left - tableBoundRect.left;
const minColLen = 30;
const minResizeLineLeft = colLeft + minColLen;

// 开始拖拽,记录下鼠标起始位置
resizeLineParams.isDragging = true;
resizeLineParams.draggingStart = e.x;

// 初始化resizeline标记线
if (resizeLineRef?.value) {
resizeLineStyle.display = 'block';
resizeLineStyle.left = `${resizeLinePos}px`;
resizeLineStyle.height = `${tableElmRef.value?.clientHeight}px`;
}

// 拖拽时鼠标可能会超出table范围,需要给docuemnt绑定拖拽相关事件
const onDragEnd = () => {
if (resizeLineParams.isDragging) {
// 结束拖拽,更新列宽
const width = parseInt(resizeLineStyle.left, 10) - colLeft;

// eslint-disable-next-line
col.width = `${Math.floor(width)}px`;

// 恢复设置
resizeLineParams.isDragging = false;
resizeLineParams.draggingCol = null;
target.style.cursor = '';
resizeLineStyle.display = 'none';
resizeLineStyle.left = '0';
document.removeEventListener('mousemove', onDragOver);
document.removeEventListener('mouseup', onDragEnd);
document.onselectstart = null;
document.ondragstart = null;
}
};

const onDragOver = (e: MouseEvent) => {
// 计算新的列宽,新列宽不得小于最小列宽
if (resizeLineParams.isDragging) {
// 更新resizeLine的位置
resizeLineStyle.left = `${Math.max(resizeLinePos + e.x - resizeLineParams.draggingStart, minResizeLineLeft)}px`;
}
};

document.addEventListener('mouseup', onDragEnd);
document.addEventListener('mousemove', onDragOver);

// 禁用鼠标的选中文字和拖放
document.onselectstart = () => false;
document.ondragstart = () => false;
};

return {
resizeLineRef,
resizeLineStyle,
onColumnMouseover,
onColumnMousedown,
};
}
12 changes: 12 additions & 0 deletions src/table/thead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export interface TheadProps {
leafColumns: BaseTableCol<TableRowData>[];
};
thList: BaseTableCol<TableRowData>[][];
columnResizeParams: {
resizeLineRef: HTMLDivElement;
resizeLineStyle: Object;
onColumnMouseover: Function;
onColumnMousedown: Function;
};
}

export default defineComponent({
Expand All @@ -38,6 +44,7 @@ export default defineComponent({
isMultipleHeader: Boolean,
spansAndLeafNodes: Object as PropType<TheadProps['spansAndLeafNodes']>,
thList: Array as PropType<TheadProps['thList']>,
columnResizeParams: Object as PropType<TheadProps['columnResizeParams']>,
},

setup(props: TheadProps, { slots }: SetupContext) {
Expand All @@ -53,13 +60,16 @@ export default defineComponent({
[tableHeaderClasses.multipleHeader]: props.isMultipleHeader,
},
]);
const { onColumnMouseover, onColumnMousedown } = props.columnResizeParams;

return {
...classnames,
theadRef,
theadClasses,
classPrefix,
slots,
onColumnMouseover,
onColumnMousedown,
};
},

Expand Down Expand Up @@ -110,6 +120,8 @@ export default defineComponent({
class={thClasses}
style={styles}
attrs={{ ...rowspanAndColspan }}
onmousemove={(e: MouseEvent) => this.onColumnMouseover(e)}
onmousedown={(e: MouseEvent) => this.onColumnMousedown(e, col)}
>
<div class={this.tableBaseClass.thCellInner}>
{col.ellipsis ? (
Expand Down
Loading

0 comments on commit c1e5133

Please sign in to comment.