VUE a-table 动态拖动修改列宽+固定列
标签,分别用来显示拖拽图标(cursor: col-resize),和蓝色标记线(有的时候鼠标移动过程中不一定会在表内,这个时候不显示图标,只显示蓝色标记线)
·
实现效果
实现思路
- 自定义表头,在标题后面加两个标签,分别用来显示拖拽图标(cursor: col-resize),和蓝色标记线(有的时候鼠标移动过程中不一定会在表内,这个时候不显示图标,只显示蓝色标记线)
- 给所有列增加一个初始宽度,表格 scroll 的 x 设置为100%
- 点击拖拽图标后:显示对应的蓝色标记线,监听鼠标的移动和释放
- 鼠标移动的时候同步更新列宽
- 鼠标释放的时候移除监听
实现代码
html
<a-table
:scroll="{ x: '100%' }"
:columns="columns"
:data-source="dataSource"
>
<template #headerCell="{ column }">
<div class="resizable-header">
<span style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis">{{ column.title }}</span>
<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') {
obj = { ...obj, width: 200, fixed: 'right' };
} else {
obj = { ...obj, width: (obj.title || '').length * 20 + 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;
let animationFrameId: any; // 为了让移动更丝滑
const mouseMoveHandler = (e: MouseEvent) => {
if (!isResizing.value || !resizingColumnKey.value) return;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(() => {
const newWidth = Math.max(50, startWidth + (e.clientX - startX));
if (newWidth !== column.width) {
column.width = newWidth;
}
});
};
const mouseUpHandler = () => {
isResizing.value = false;
resizingColumnKey.value = '';
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
};
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: 2;
width: 6px;
height: 100%;
cursor: col-resize;
}
.resizer-line {
position: absolute;
top: -8px;
right: -8px;
bottom: -8px;
width: 1px;
background-color: #3388FF;
}
}
更多推荐
所有评论(0)