实现效果
实现思路
- 自定义表头,在标题后面加两个标签,分别用来显示拖拽图标(cursor: col-resize),和蓝色标记线(有的时候鼠标移动过程中不一定会在表内,这个时候不显示图标,只显示蓝色标记线)
- 给所有列增加一个初始宽度,表格 scroll 的 x 设置为100%
- 点击拖拽图标后:显示对应的蓝色标记线,监听鼠标的移动和释放
- 鼠标移动的时候同步更新列宽
- 鼠标释放的时候移除监听
实现代码
html
<a-table
:scroll="{ x: '100%' }"
:columns="columns"
:data-source="dataSource"
>
<template #headerCell="{ column }">
<div class="resizable-header">
{{ column.title }}
<span class="resizer" @mousedown="(e) => onMouseDown(e, column)"></span>
<span v-if="isResizing && resizingColumnKey === column.key" class="resizer-line"></span>
</div>
</template>
</a-table>
ts
const columns = ref<Array<any>>([]);
const isResizing = ref(false);
const resizingColumnKey = ref<string>('');
watch(
() => headerColumns.value,
() => {
columns.value = headerColumns.value.map((obj: HeaderColumns) => {
if (item.name === 'code') {
obj = { ...obj, width: 150, fixed: true };
} else if (item.name === 'seq') {
obj = { ...obj, width: 50, fixed: true };
} else if (item.name === 'operation') {
delete obj.ellipsis;
obj = { ...obj, width: 200, fixed: 'right' };
} else {
obj = { ...obj, width: (obj.title || '').length * 15 + 18 };
}
return obj;
});
},
{
immediate: true,
deep: true,
},
);
const onMouseDown = (event: MouseEvent, column: any) => {
const startX = event.clientX;
const startWidth = column.width || 0;
isResizing.value = true;
resizingColumnKey.value = column.key;
const mouseMoveHandler = (e: MouseEvent) => {
if (!isResizing.value || !resizingColumnKey.value) return;
const newWidth = Math.max(50, parseFloat(`${startWidth}`) + (e.clientX - startX));
column.width = newWidth;
};
const mouseUpHandler = () => {
isResizing.value = false;
resizingColumnKey.value = '';
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
css
:deep(.ant-table-cell-ellipsis.ant-table-cell-fix-left-last .ant-table-cell-content) {
overflow: visible;
}
.resizable-header {
position: relative;
display: flex;
align-items: center;
.resizer {
position: absolute;
top: 0;
right: -12px;
z-index: 1;
width: 8px;
height: 100%;
cursor: col-resize;
}
.resizer-line {
position: absolute;
top: -8px;
right: -8px;
bottom: -8px;
width: 1px;
background-color: #3388FF;
}
}