You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现带嵌套子行的Vuetify可拖拽数据表?

实现带父子行拖拽的Vuetify数据表

核心修改思路

要实现父行展开显示子行且子行支持拖拽,需要解决三个核心问题:父行独立的展开状态、子行的正确渲染、拖拽事件的层级适配。


步骤1:改造父行展开状态

把全局的show变量改为每个父行对象的独立属性,避免所有父行同时展开/折叠:

<v-icon
  v-if="!_.isEmpty(item.children)" 
  color="#68007d"
  @click="item.isExpanded = !item.isExpanded"
>
  {{ item.isExpanded ? 'remove_circle' : 'add_circle' }}
</v-icon>

初始化数据时给有子项的父行添加isExpanded属性:

// 数据加载完成后执行
this.props.items.forEach(item => {
  if (!_.isEmpty(item.children)) {
    item.isExpanded = false; // 默认折叠
  }
});

步骤2:渲染子行

在父行的<tr>后添加子行的循环渲染,注意用colspan对齐列数,添加缩进提升视觉区分:

<!-- 父行 -->
<tr
  v-for="(item, index) in props.items"
  :key="`parent-${index}`"
  @drop="dropIntoParentRelationship($event, index)"
  @dragover.prevent
  @dragenter.prevent
  @dragstart="startDrag($event, item, index)" 
>
  <!-- 父行列内容保持原有逻辑不变 -->
</tr>

<!-- 子行 -->
<tr
  v-if="item.isExpanded && !_.isEmpty(item.children)"
  v-for="(child, childIndex) in item.children"
  :key="`child-${index}-${childIndex}`"
  @drop="dropIntoParentRelationship($event, index, true, childIndex)"
  @dragover.prevent
  @dragenter.prevent
  @dragstart="startDrag($event, child, childIndex, true, index)"
>
  <td colspan="2" style="padding-left: 20px;">
    <v-icon size="small">fiber_manual_record</v-icon>
  </td>
  <td>
    <div class="text-truncate" style="max-width: 230px;">{{ child.product_title }}</div>
  </td>
  <td>
    <div class="text-truncate" style="max-width: 230px;">{{ child.sku }}</div>
  </td>
  <td class="text-center">
    <country-flag :country='countryFlags[child.marketplace]' size='normal' class='text-center' />
  </td>
  <td class="text-center">
    <p class="mt-4">{{child.quantity}}</p>
  </td>
  <td>
    <p class="mt-4">{{child.currency_symbol}}{{child.price}}</p>
  </td>
  <td class="text-center">
    <v-icon :color="child.on_shopify ? 'green darken-4' : 'red darken-4'">
      {{ child.on_shopify ? 'done' : 'close' }}
    </v-icon>
  </td>
  <td class="text-center">
    <v-icon :color="child.uploaded ? 'green darken-4' : 'red darken-4'">
      {{ child.uploaded ? 'done' : 'close' }}
    </v-icon>
  </td>
</tr>

步骤3:适配拖拽事件

扩展拖拽事件,区分父行/子行类型,处理不同的拖拽场景:

startDrag(event, item, index, isChild = false, parentIndex = null) {
  // 存储拖拽关键信息:数据、类型、索引、父级索引
  event.dataTransfer.setData('dragData', JSON.stringify({
    item,
    index,
    isChild,
    parentIndex
  }));
}

dropIntoParentRelationship(event, targetIndex, isTargetChild = false, targetChildIndex = null) {
  const dragData = JSON.parse(event.dataTransfer.getData('dragData'));
  const { item: draggedItem, index: draggedIndex, isChild, parentIndex } = dragData;

  if (isChild) {
    // 场景1:拖拽子行
    const sourceParent = this.props.items[parentIndex];
    // 从原父行移除子行
    sourceParent.children.splice(draggedIndex, 1);

    if (!isTargetChild) {
      // 拖拽到父行:添加为目标父行的子项
      const targetParent = this.props.items[targetIndex];
      targetParent.children.push(draggedItem);
    } else {
      // 拖拽到同父行的其他子行:调整子行顺序
      const targetParent = this.props.items[targetIndex];
      targetParent.children.splice(targetChildIndex, 0, draggedItem);
    }
  } else {
    // 场景2:拖拽父行,保持原有重排逻辑
    const dragged = this.props.items.splice(draggedIndex, 1)[0];
    this.props.items.splice(targetIndex, 0, dragged);
  }
}

注意事项

  • 确保子行的colspan数量和父行的列数一致,避免表格布局错乱
  • 拖拽子行时,需判断目标是父行还是子行,分别处理跨父移动和内部重排
  • 可以通过样式(如缩进、小图标)强化父子行的视觉层级,提升用户体验

内容的提问来源于stack exchange,提问作者ToddT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:00:39