vue 甘特图 vxe-gantt 实现 table 表格与甘特图拖拽双向联动、拖拽添加,拖拽移除 在复杂的项目管理场景中任务数据往往分散在不同的视图中——一部分任务在表格中展示另一部分在甘特图中呈现。如果能让用户在表格和甘特图之间自由拖拽任务实现数据的跨视图联动将极大提升任务编排的效率。vxe-gantt 通过 row-drag-config.isCrossTableDrag 配置支持表格组件与甘特图组件之间的跨表拖拽让任务可以在不同组件间自由移动。同时内置的 CRUD 管理器会自动记录每次拖拽产生的数据变更新增、删除、修改方便开发者进行后续处理。本文介绍跨表拖拽的配置方法、核心机制与完整示例。核心配置跨表拖拽需要同时配置源组件和目标组件两者缺一不可配置项类型说明rowConfig.dragBoolean必须设为 true启用行拖拽功能。rowConfig.keyFieldString必须指定数据唯一主键字段名如 ‘id’确保跨表拖拽时数据不混乱。rowDragConfig.isCrossTableDragBoolean必须设为 true允许跨表格/跨组件拖拽。rowDragConfig.isCrossDragBoolean建议设为 true允许跨层级拖拽如果数据有父子结构。treeConfigObject如果数据为树形结构需配置 transform: true、rowField 和 parentField。重要提醒跨表拖拽要求所有参与拖拽的表格/甘特图使用相同的主键字段名由 keyField 指定且数据主键不能重复否则拖拽将导致数据错乱或报错。核心机制CRUD 管理器自动追踪变更跨表拖拽的本质是数据的跨组件移动——当用户将一个任务从表格拖到甘特图时源组件会删除该行数据目标组件会新增该行数据。vxe-gantt 内置的 CRUD 管理器会自动记录这些操作开发者可以通过 getRecordset() 方法获取完整的变更记录集const { insertRecords, removeRecords, updateRecords } $table.getRecordset()返回值说明insertRecords新增的数据行拖拽进入的目标组件removeRecords删除的数据行拖拽离开的源组件updateRecords修改的数据行这一机制让开发者无需手动追踪数据变化直接调用 API 即可获得完整的操作清单便于提交后端进行持久化。代码表格组件与一个甘特图组件之间的双向拖拽联动。templatedivvxe-buttonstatussuccessclickresultEvent1获取数据1/vxe-buttonvxe-gridrefgridRef1v-bindgridOptions1/vxe-griddivstylebackground-color:antiquewhite;line-height:60px;margin:32px 0支持上方表格与下方甘特图互相拖拽任务/divvxe-buttonstatussuccessclickresultEvent2获取数据2/vxe-buttonvxe-ganttrefganttRef2v-bindganttOptions2/vxe-gantt/div/templatescriptsetupimport{ref,reactive}fromvueimport{VxeUI}fromvxe-pc-uiconstgridRef1ref()constgridOptions1reactive({border:true,height:400,rowConfig:{drag:true,keyField:id},rowDragConfig:{isCrossDrag:true,// 允许跨级isCrossTableDrag:true// 允许跨表},treeConfig:{transform:true,rowField:id,parentField:parentId},columns:[{type:seq,width:70},{field:id,title:ID,width:70},{field:title,title:任务名称,minWidth:160,treeNode:true,dragSort:true},{field:start,title:开始时间,width:100},{field:end,title:结束时间,width:100},{field:progress,title:进度,width:100}],data:[{id:10001,parentId:null,title:A项目,start:2024-03-01,end:2024-03-04,progress:3},{id:10002,parentId:10001,title:城市道路修理进度,start:2024-03-03,end:2024-03-08,progress:10},{id:10003,parentId:null,title:B大工程,start:2024-03-03,end:2024-03-11,progress:90},{id:10004,parentId:10003,title:超级大工程,start:2024-03-05,end:2024-03-11,progress:15},{id:10005,parentId:10003,title:地球净化项目,start:2024-03-08,end:2024-03-15,progress:100},{id:10006,parentId:10003,title:一个小目标项目,start:2024-03-10,end:2024-03-21,progress:0},{id:10007,parentId:10005,title:某某计划,start:2024-03-15,end:2024-03-24,progress:70}]})constresultEvent1(){const$gridgridRef1.valueif($grid){const{insertRecords,removeRecords}$grid.getRecordset()consttableData$grid.getFullData()VxeUI.modal.message({content:新增${insertRecords.length}删除${removeRecords.length}现有${tableData.length},status:success})}}constganttRef2ref()constganttOptions2reactive({border:true,height:400,rowConfig:{drag:true,keyField:id},rowDragConfig:{isCrossDrag:true,// 允许跨级isCrossTableDrag:true// 允许跨表},treeConfig:{transform:true,rowField:id,parentField:parentId},taskBarConfig:{showProgress:true,// 是否显示进度条showContent:true,// 是否在任务条显示内容moveable:true,// 是否允许拖拽任务移动日期resizable:true,// 是否允许拖拽任务调整日期barStyle:{round:true,// 圆角bgColor:#fca60b,// 任务条的背景颜色completedBgColor:#65c16f// 已完成部分任务条的背景颜色}},columns:[{type:seq,width:70},{field:title,title:任务名称,minWidth:160,treeNode:true,dragSort:true},{field:start,title:开始时间,width:100},{field:end,title:结束时间,width:100}],data:[{id:10008,parentId:null,title:某某科技项目,start:2024-03-20,end:2024-03-29,progress:50},{id:10009,parentId:10008,title:地铁建设工程,start:2024-03-19,end:2024-03-20,progress:5},{id:10010,parentId:10008,title:公寓装修计划2,start:2024-03-12,end:2024-03-20,progress:30},{id:10011,parentId:10008,title:两个小目标工程,start:2024-03-01,end:2024-03-04,progress:20},{id:10012,parentId:null,title:蓝天计划,start:2024-03-02,end:2024-03-08,progress:50},{id:10013,parentId:10010,title:C大项目,start:2024-03-08,end:2024-03-11,progress:10},{id:10014,parentId:10010,title:H计划,start:2024-03-12,end:2024-03-16,progress:100},{id:10015,parentId:10011,title:铁路修建计划,start:2024-03-05,end:2024-03-06,progress:0},{id:10016,parentId:10011,title:D项目,start:2024-03-06,end:2024-03-11,progress:10},{id:10017,parentId:10011,title:海外改造工程,start:2024-03-08,end:2024-03-09,progress:0}]})constresultEvent2(){const$ganttganttRef2.valueif($gantt){const{insertRecords,removeRecords}$gantt.getRecordset()consttableData$gantt.getFullData()VxeUI.modal.message({content:新增${insertRecords.length}删除${removeRecords.length}现有${tableData.length},status:success})}}/script说明1. 主键唯一性最重要跨表拖拽依赖主键来识别数据行。所有参与拖拽的组件必须使用相同的主键字段名通过 keyField 指定且所有数据的主键值全局唯一——不能出现两个组件中有相同 id 的任务。如果主键重复拖拽时组件无法区分数据归属会导致数据错乱或报错2. 树形结构的支持如果数据存在父子层级如示例中的 parentId 字段需要配置 treeConfigtreeConfig:{transform:true,// 启用树形数据转换rowField:id,// 行主键字段parentField:parentId// 父级关联字段}配合 isCrossDrag: true可以支持跨层级的拖拽如将子任务拖拽为另一个父任务的子任务。3. 拖拽把手的设置在 columns 中需要至少有一列设置 dragSort: true 作为拖拽把手{field:title,title:任务名称,dragSort:true}需要拖拽该列所在的行或单元格才能触发拖拽行为。CRUD 管理器 API 速查方法返回值说明getRecordset(){ insertRecords, removeRecords, updateRecords }获取完整的变更记录集。getFullData()Array获取当前所有数据包含拖拽后的最终状态。getInsertRecords()Array仅获取新增的数据行。getRemoveRecords()Array仅获取被删除的数据行。getUpdateRecords()Array仅获取被修改的数据行。vxe-gantt 的跨表拖拽功能通过 row-drag-config.isCrossTableDrag 配置实现了表格与甘特图之间的双向数据联动。其核心优势在于✅ 配置简单只需同时开启源和目标组件的 isCrossTableDrag。✅ 自动追踪内置 CRUD 管理器自动记录每一次拖拽产生的数据变更。✅ 树形支持配合 treeConfig 可支持带父子层级的数据拖拽。✅ 灵活联动不仅支持表格 ↔ 甘特图也支持多个表格或甘特图之间的互相拖拽。只需确保数据主键全局唯一并正确配置两端组件即可快速实现跨视图的任务编排能力。https://gantt.vxeui.com