当前位置:首页 > 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属性实现宽度同步:

<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属性减少重排开销:

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如何实现拖动

Vue 实现拖动的几种方法 使用 HTML5 原生拖放 API HTML5 提供了原生的拖放 API,通过 draggable 属性和相关事件实现拖动功能。 <template>…

vue实现表格复选

vue实现表格复选

Vue实现表格复选的方法 基础实现 在Vue中实现表格复选功能可以通过v-model绑定复选框的状态,结合v-for循环渲染表格数据。以下是一个基础示例: <template> &l…

css好看的表格制作

css好看的表格制作

CSS表格美化方法 边框与间距优化 使用border-collapse合并边框,避免双线边框。设置padding增加单元格内边距,提升可读性。 table { border-collapse:…

css表格制作

css表格制作

CSS 表格制作基础 使用 CSS 可以创建美观且响应式的表格。以下是一些基本方法: table 元素用于定义表格,tr 定义行,td 定义单元格,th 定义表头单元格。 <table>…

vue实现数据拖动

vue实现数据拖动

Vue 实现数据拖动 在 Vue 中实现数据拖动通常涉及 HTML5 的拖放 API 或第三方库(如 vuedraggable)。以下是两种常见方法: 使用 HTML5 拖放 API 设置拖拽元…

vue实现简单表格

vue实现简单表格

Vue 实现简单表格的方法 使用原生 HTML 表格 在 Vue 模板中可以直接使用 HTML 原生表格标签,通过 v-for 动态渲染数据: <template> <tabl…