Vue.draggable实现两个可拖拽表格间的交换功能问题咨询
实现两个可拖拽表格的条目交换功能
核心配置要点
- 两个
<draggable>组件需设置相同的group名称,开启跨列表拖拽权限 - 表格1固定7条数据,限制为交换模式:拖拽表格2条目到表格1时,替换目标位置原有条目,而非新增
- 跨列表拖拽触发时弹出确认对话框,用户确认后执行交换,否则回滚数据
- 可通过钩子禁止表格1内部拖拽排序,保留固定条目的结构
完整代码实现
<template> <div class="table-container"> <!-- 表格1:固定7条条目 --> <table> <thead> <tr><th>ID</th><th>姓名</th><th>年龄</th></tr> </thead> <draggable v-model="table1Items" tag="tbody" :group="{ name: 'table-group' }" @end="handleDragEnd" :move="handleMove" :options="{ animation: 500 }" > <tr v-for="item in table1Items" :key="item.id"> <td>{{ item.id }}</td> <td>{{ item.name }}</td> <td>{{ item.age }}</td> </tr> </draggable> </table> <!-- 表格2:其他条目 --> <table> <thead> <tr><th>ID</th><th>姓名</th><th>年龄</th></tr> </thead> <draggable v-model="table2Items" tag="tbody" :group="{ name: 'table-group' }" @end="handleDragEnd" :options="{ animation: 500 }" > <tr v-for="item in table2Items" :key="item.id"> <td>{{ item.id }}</td> <td>{{ item.name }}</td> <td>{{ item.age }}</td> </tr> </draggable> </table> </div> </template> <script> import draggable from "vuedraggable"; export default { components: { draggable }, data() { return { // 表格1:固定7条示例数据 table1Items: [ { id: 1, name: "Alice", age: 25 }, { id: 2, name: "Bob", age: 30 }, { id: 3, name: "Charlie", age: 28 }, { id: 4, name: "David", age: 35 }, { id: 5, name: "Eve", age: 22 }, { id: 6, name: "Frank", age: 40 }, { id: 7, name: "Grace", age: 27 } ], // 表格2:其他示例数据 table2Items: [ { id: 8, name: "Henry", age: 32 }, { id: 9, name: "Iris", age: 24 }, { id: 10, name: "Jack", age: 38 } ], // 保存拖拽前的状态,用于取消时回滚 prevState: {} }; }, methods: { handleMove(evt) { // 禁止表格1内部的拖拽排序 const isSameTable1 = evt.from._vnode.data.model.value === this.table1Items && evt.to._vnode.data.model.value === this.table1Items; return !isSameTable1; }, handleDragEnd(evt) { const { draggedContext, to, from } = evt; // 同列表拖拽直接返回 if (from === to) return; // 判断是否是表格2到表格1的跨列表拖拽 const isCrossDrag = from._vnode.data.model.value === this.table2Items && to._vnode.data.model.value === this.table1Items; if (!isCrossDrag) return; // 保存拖拽前的完整状态 this.prevState = { table1: [...this.table1Items], table2: [...this.table2Items], draggedItem: draggedContext.item, targetIndex: evt.toIndex, sourceIndex: draggedContext.index }; // 弹出确认对话框 const confirmSwap = confirm('确定要交换这两个条目吗?'); if (confirmSwap) { // 执行交换逻辑 const table1TargetItem = this.table1Items[this.prevState.targetIndex]; // 移除表格2的拖拽项 this.table2Items.splice(this.prevState.sourceIndex, 1); // 替换表格1目标位置的条目 this.table1Items.splice(this.prevState.targetIndex, 1, this.prevState.draggedItem); // 将表格1原条目添加到表格2 this.table2Items.push(table1TargetItem); } else { // 用户取消,回滚到拖拽前状态 this.table1Items = this.prevState.table1; this.table2Items = this.prevState.table2; } } } }; </script> <style scoped> .table-container { display: flex; gap: 20px; padding: 20px; } table { border-collapse: collapse; border: 1px solid #ddd; min-width: 300px; } th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; } th { background-color: #f5f5f5; } tr:hover { background-color: #f9f9f9; } </style>
关键逻辑说明
- 跨列表拖拽配置:两个
<draggable>的group.name设为相同值,允许组件间的拖拽交互。 - 内部拖拽拦截:通过
handleMove钩子禁止表格1内部的拖拽排序,确保只能进行跨列表交换。 - 拖拽状态判断:在
handleDragEnd中通过数据源判断是否为表格2到表格1的跨列表操作,过滤无效交互。 - 确认与回滚:拖拽前保存两个表格的原始数据,用户取消时直接恢复;确认后执行交换逻辑,保证表格1始终保持7条数据。
- 交换逻辑实现:移除表格2的拖拽项,替换表格1目标位置的条目,再将表格1原条目添加到表格2,完成双向交换。
内容的提问来源于stack exchange,提问作者OMFGDom
相关产品推荐
相关产品推荐

