vue实现表格拖动列宽
实现表格列宽拖动的核心思路
通过监听鼠标事件(mousedown、mousemove、mouseup)动态修改列宽度。需要处理表头单元格的拖拽手柄,计算鼠标移动距离并更新列宽。
基本实现步骤
创建可拖拽的表头单元格,添加拖拽手柄元素:
<template>
<table>
<thead>
<tr>
<th v-for="(col, index) in columns" :key="index">
<div class="header-content">
{{ col.title }}
<div
class="resize-handle"
@mousedown="startResize(index, $event)"
></div>
</div>
</th>
</tr>
</thead>
<tbody>
<!-- 表格数据行 -->
</tbody>
</table>
</template>
添加CSS样式确保拖拽手柄可见:
.resize-handle {
width: 5px;
height: 100%;
background: #ccc;
cursor: col-resize;
position: absolute;
right: 0;
top: 0;
}
th {
position: relative;
padding-right: 15px; /* 为手柄留空间 */
}
实现拖拽逻辑的JavaScript部分:

export default {
data() {
return {
columns: [
{ title: '列1', width: 150 },
{ title: '列2', width: 200 }
],
isResizing: false,
currentColumn: null,
startX: 0,
startWidth: 0
}
},
methods: {
startResize(index, e) {
this.isResizing = true
this.currentColumn = index
this.startX = e.clientX
this.startWidth = this.columns[index].width
document.addEventListener('mousemove', this.handleResize)
document.addEventListener('mouseup', this.stopResize)
},
handleResize(e) {
if (!this.isResizing) return
const dx = e.clientX - this.startX
this.columns[this.currentColumn].width = this.startWidth + dx
},
stopResize() {
this.isResizing = false
document.removeEventListener('mousemove', this.handleResize)
document.removeEventListener('mouseup', this.stopResize)
}
}
}
性能优化建议
使用CSS transforms代替直接修改宽度减少重排:
handleResize(e) {
if (!this.isResizing) return
const dx = e.clientX - this.startX
this.$refs.table.querySelectorAll('th')[this.currentColumn].style.width =
`${this.startWidth + dx}px`
}
添加防抖处理避免频繁更新:

import { debounce } from 'lodash'
methods: {
handleResize: debounce(function(e) {
// 处理逻辑
}, 16) // 约60fps
}
完整组件示例
结合表格数据的完整组件实现:
<template>
<div class="resizable-table">
<table ref="table">
<thead>
<tr>
<th
v-for="(col, index) in columns"
:key="index"
:style="{ width: col.width + 'px' }"
>
<div class="header-content">
{{ col.title }}
<div
class="resize-handle"
@mousedown="startResize(index, $event)"
></div>
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td
v-for="(col, colIndex) in columns"
:key="colIndex"
:style="{ width: columns[colIndex].width + 'px' }"
>
{{ row[col.key] }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
边界情况处理
防止列宽过小:
handleResize(e) {
if (!this.isResizing) return
const dx = e.clientX - this.startX
const newWidth = Math.max(30, this.startWidth + dx) // 最小30px
this.columns[this.currentColumn].width = newWidth
}
处理表格滚动情况:
startResize(index, e) {
// 获取表格相对于视口的位置
const rect = this.$refs.table.getBoundingClientRect()
this.startX = e.clientX - rect.left
// 其他逻辑...
}






