用 Vue 3 实现一个拖拽排序表格组件(支持列/行重排、列宽调整)

一、项目初始化

1.1 技术栈说明

  • Vue 3 Composition API
  • vuedraggable:用于实现拖拽排序
  • 原生 DOM 操作:用于列宽调整
  • Element Plus(可选):用于样式和表格基础结构

1.2 项目结构图(Mermaid)

App.vue
TableComponent.vue
RowDraggable.vue
ColResizable.vue

二、构建基础表格组件

2.1 创建基本表格结构

<!-- TableComponent.vue -->
<template>
  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th v-for="(col, index) in columns" :key="col.key">
            {{ col.label }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, rowIndex) in tableData" :key="row.id">
          <td v-for="col in columns" :key="col.key">{{ row[col.key] }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const columns = ref([
  { label: '姓名', key: 'name' },
  { label: '年龄', key: 'age' },
  { label: '地址', key: 'address' }
])

const tableData = ref([
  { id: 1, name: '小明', age: 25, address: '北京' },
  { id: 2, name: '小红', age: 30, address: '上海' },
  { id: 3, name: '小刚', age: 28, address: '广州' }
])
</script>

三、实现行拖拽排序

3.1 安装依赖

npm install vuedraggable

3.2 使用 vuedraggable 实现拖拽

<template>
  <draggable v-model="tableData" tag="tbody" item-key="id">
    <tr v-for="row in tableData" :key="row.id">
      <td v-for="col in columns" :key="col.key">{{ row[col.key] }}</td>
    </tr>
  </draggable>
</template>

<script setup>
import draggable from 'vuedraggable'
</script>

四、实现列宽拖拽调整

4.1 基本样式设置

th {
  position: relative;
  padding-right: 8px;
}

.resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 5px;
  cursor: col-resize;
  user-select: none;
}

4.2 添加拖拽逻辑

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

let startX, startWidth

const startResize = (e, index) => {
  startX = e.clientX
  startWidth = columns.value[index].width || 100
  document.addEventListener('mousemove', resize)
  document.addEventListener('mouseup', stopResize)

  function resize(e) {
    const newWidth = startWidth + (e.clientX - startX)
    columns.value[index].width = Math.max(newWidth, 60)
  }

  function stopResize() {
    document.removeEventListener('mousemove', resize)
    document.removeEventListener('mouseup', stopResize)
  }
}

五、实现列拖拽排序

5.1 转换列为可拖拽结构

<draggable v-model="columns" tag="tr" item-key="key" direction="horizontal">
  <th
    v-for="(col, index) in columns"
    :key="col.key"
    :style="{ width: col.width + 'px' }"
    @mousedown="startResize($event, index)"
  >
    {{ col.label }}
    <span class="resizer"></span>
  </th>
</draggable>

5.2 保证数据对应正确列

<tr v-for="row in tableData" :key="row.id">
  <td v-for="col in columns" :key="col.key">
    {{ row[col.key] }}
  </td>
</tr>

六、可拓展功能实现

6.1 固定列实现(示意)

<th :class="{ 'sticky-left': index === 0 }"> ... </th>
.sticky-left {
  position: sticky;
  left: 0;
  background-color: #fff;
  z-index: 2;
}

6.2 列顺序保存到本地存储

watch(columns, (val) => {
  localStorage.setItem('columns', JSON.stringify(val))
}, { deep: true })

onMounted(() => {
  const saved = localStorage.getItem('columns')
  if (saved) {
    columns.value = JSON.parse(saved)
  }
})

七、总结

通过本文,我们使用 Vue 3 实现了一个具备以下功能的可配置表格组件:

  • ✅ 行拖拽排序
  • ✅ 列宽度调整
  • ✅ 列顺序拖拽
  • ✅ 固定列支持
  • ✅ 用户列设置持久化

该组件可广泛应用于数据管理后台、内容管理系统等场景,未来可继续拓展如列隐藏、分组列头、自定义渲染等功能。


到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 前端 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」🚀 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
📢 特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~ 💕

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值