当前位置:首页 > VUE

vue实现表格拖动列宽

2026-01-12 07:25:40VUE

实现表格列宽拖动的核心思路

通过监听鼠标事件(mousedown、mousemove、mouseup)实现拖拽逻辑,动态修改列宽。需要处理表头与表体的联动,确保拖动时视觉一致。

基础HTML结构

<template>
  <div class="draggable-table">
    <table>
      <thead>
        <tr>
          <th v-for="(col, index) in columns" :key="index" 
              @mousedown="startResize(index, $event)">
            {{ col.title }}
            <div class="resize-handle"></div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, rowIndex) in data" :key="rowIndex">
          <td v-for="(col, colIndex) in columns" :key="colIndex">
            {{ row[col.key] }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

CSS样式关键部分

.resize-handle {
  position: absolute;
  right: 0;
  top: 0;
  width: 5px;
  height: 100%;
  background: transparent;
  cursor: col-resize;
}

th {
  position: relative;
  user-select: none;
}

table {
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 1px solid #ddd;
  padding: 8px;
}

JavaScript核心逻辑

export default {
  data() {
    return {
      columns: [
        { title: '姓名', key: 'name', width: 150 },
        { title: '年龄', key: 'age', width: 100 },
        { title: '地址', key: 'address', width: 300 }
      ],
      data: [
        { name: '张三', age: 25, address: '北京' },
        { name: '李四', age: 30, address: '上海' }
      ],
      isResizing: false,
      startX: 0,
      startWidth: 0,
      resizeIndex: null
    }
  },
  methods: {
    startResize(index, e) {
      this.isResizing = true
      this.resizeIndex = 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 newWidth = this.startWidth + (e.clientX - this.startX)
      this.columns[this.resizeIndex].width = Math.max(30, newWidth)
    },
    stopResize() {
      this.isResizing = false
      document.removeEventListener('mousemove', this.handleResize)
      document.removeEventListener('mouseup', this.stopResize)
    }
  }
}

动态绑定列宽

在HTML中绑定style属性实现宽度同步:

vue实现表格拖动列宽

<th v-for="(col, index) in columns" :key="index" 
    :style="{ width: col.width + 'px' }"
    @mousedown="startResize(index, $event)">
  {{ col.title }}
  <div class="resize-handle"></div>
</th>

<td v-for="(col, colIndex) in columns" :key="colIndex"
    :style="{ width: columns[colIndex].width + 'px' }">
  {{ row[col.key] }}
</td>

性能优化建议

使用CSS的will-change: width属性减少重排开销:

vue实现表格拖动列宽

th, td {
  will-change: width;
}

添加拖动时的视觉反馈:

.is-resizing {
  background-color: #f0f0f0;
}

在拖动时动态添加class:

handleResize(e) {
  if (!this.isResizing) return
  document.body.classList.add('is-resizing')
  // ...原有逻辑
},
stopResize() {
  document.body.classList.remove('is-resizing')
  // ...原有逻辑
}

完整组件示例

<template>
  <div class="draggable-table">
    <table>
      <thead>
        <tr>
          <th v-for="(col, index) in columns" :key="index" 
              :style="{ width: col.width + 'px' }"
              @mousedown="startResize(index, $event)">
            {{ col.title }}
            <div class="resize-handle"></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>

<script>
export default {
  data() {
    return {
      columns: [
        { title: '姓名', key: 'name', width: 150 },
        { title: '年龄', key: 'age', width: 100 },
        { title: '地址', key: 'address', width: 300 }
      ],
      data: [
        { name: '张三', age: 25, address: '北京' },
        { name: '李四', age: 30, address: '上海' }
      ],
      isResizing: false,
      startX: 0,
      startWidth: 0,
      resizeIndex: null
    }
  },
  methods: {
    startResize(index, e) {
      if (e.target.classList.contains('resize-handle') || e.offsetX > this.columns[index].width - 10) {
        this.isResizing = true
        this.resizeIndex = 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
      document.body.classList.add('is-resizing')
      const newWidth = this.startWidth + (e.clientX - this.startX)
      this.$set(this.columns, this.resizeIndex, {
        ...this.columns[this.resizeIndex],
        width: Math.max(30, newWidth)
      })
    },
    stopResize() {
      document.body.classList.remove('is-resizing')
      this.isResizing = false
      document.removeEventListener('mousemove', this.handleResize)
      document.removeEventListener('mouseup', this.stopResize)
    }
  }
}
</script>

标签: 拖动表格
分享给朋友:

相关文章

vue实现重置表格数据

vue实现重置表格数据

重置表格数据的方法 在Vue中重置表格数据通常涉及清空或重新初始化数据绑定的数组或对象。以下是几种常见实现方式: 直接重置数据源 对于基于数组的表格数据,可以直接将数据数组重置为空或初始值:…

css 制作表格

css 制作表格

CSS 制作表格的方法 使用 CSS 制作表格可以通过多种方式实现,包括原生 HTML 表格样式、Flexbox 布局或 Grid 布局。以下是几种常见的方法: 原生 HTML 表格样式 HTML…

js实现图片拖动

js实现图片拖动

实现图片拖动的步骤 使用JavaScript实现图片拖动功能,可以通过HTML5的拖放API结合事件监听实现。以下是具体方法: 设置HTML结构 为图片添加draggable属性,并设置唯一ID以便…

vue 实现表格渲染

vue 实现表格渲染

基本表格渲染 在 Vue 中渲染表格通常使用 v-for 指令遍历数据数组,动态生成表格行。以下是一个简单的示例: <template> <table> <…

vue实现表格合并

vue实现表格合并

实现表格合并的方法 在Vue中实现表格合并通常涉及对表格数据的处理和单元格属性的动态绑定。以下是几种常见的方法: 使用rowspan和colspan属性 通过计算需要合并的行或列数,动态绑定rows…

vue循环实现表格

vue循环实现表格

Vue 循环实现表格的方法 在 Vue 中,可以通过 v-for 指令循环渲染表格数据。以下是一些常见的实现方式: 基础表格循环 使用 v-for 循环数组数据生成表格行: <templat…