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

如何在ag-grid扁平表格中用cell-renderer实现树形结构(不使用内置树结构)

自定义AG-Grid单元格渲染器实现树形结构(含正确连接线)

我有层级化数据,不想使用AG-Grid自带的树形数据结构展示,希望在扁平表格中通过自定义cell-renderer渲染成树形结构。目前已实现按层级设置缩进,但垂直与水平连接线无法正确显示,想要达到标准树形的连接线样式。以下是我的当前代码和数据结构:


当前实现代码

Template

<template>
  <div class="hierarchical-tree-cell">
    <div class="indentation" :style="{ width: indentationWidth }">
      <div class="vertical-line"></div>
      <div class="dotted-line"></div>
    </div>
    <div class="tree-content">
      {{ hierarchy[level] }}
    </div>
  </div>
</template>

Script

<script setup>
import { computed } from "vue";
const props = defineProps({ params: { type: Object, default: () => ({}) } });

const hierarchy = props.params.data.hierarchy;
const level = hierarchy.length - 1;

const indentationWidth = computed(() => {
  return `${level * 20}px`; // 可调整缩进倍数
});
</script>

Style

<style scoped>
.hierarchical-tree-cell {
  display: flex;
  align-items: center;
}

.tree-content {
  display: flex;
  align-items: center;
}

.indentation {
  position: relative;
  height: 100%;
  border-left: 1px solid #ccc;
}

.vertical-line {
  position: absolute;
  top: 0;
  left: 10px;
  bottom: 0;
  width: 1px;
  background-color: #ccc;
}

.dotted-line {
  content: "";
  position: absolute;
  top: 50%;
  left: 10px;
  width: 1px;
  height: 50%;
  border-left: 1px dotted #ccc;
}
</style>

数据结构示例

[
  {
    "AffectedPart": "91422146",
    "owner": "dsotest27.im",
    "physicalid": "B1009056833D00009FC7D458BE2A0400",
    "hierarchy": ["91422146"],
    "description": "test",
    "type": "Formulation Part",
    "Title": "test",
    "revision": "001",
    "current": "Preliminary",
    "Primary": "-",
    "id": "20336.41905.28416.41775",
    "ats_Operation": "",
    "ats_ReplacementRawMaterialIntermediate": "",
    "ats_Title": "",
    "ats_Revision": "",
    "ats_MinPer": "",
    "ats_WetWeightMin": "",
    "ats_QuantityWetPer": "",
    "ats_MaxPer": "",
    "ats_WetWeightMax": "",
    "ats_TargetWetWeight": "",
    "ats_ProcessingLoss": "",
    "ats_TargetDryWeight": "",
    "ats_DryPer": "",
    "ats_ProcessingNote": "",
    "Operation": "",
    "PrimaryQuantity": 0,
    "SubstituteQuantity": 0,
    "MinPer": "",
    "WetWeightMin": "",
    "QuantityWetPer": "",
    "MaxPer": "",
    "WetWeightMax": "",
    "TargetWetWeight": "",
    "ProcessingLossPer": "",
    "TargetDryWeight": "",
    "DryPer": "",
    "ProcessingNote": ""
  }
]

修正方案

当前实现的核心问题是没有区分节点是否为父节点的最后一个子节点,导致连线无法正确断开。以下是修正后的完整实现:

修正后的Template

<template>
  <div class="hierarchical-tree-cell">
    <!-- 为每个层级生成独立的缩进与连线 -->
    <div 
      v-for="(_, idx) in level" 
      :key="idx"
      class="level-indent"
      :class="{ 'last-child': isLastChildAtLevel(idx) }"
    >
      <div class="vertical-connector"></div>
    </div>
    <!-- 当前节点的前缀连线 -->
    <div class="node-prefix" :class="{ 'last-child': isLastNode }">
      <div class="horizontal-connector"></div>
    </div>
    <div class="tree-content">
      {{ hierarchy[level] }}
    </div>
  </div>
</template>

修正后的Script

<script setup>
import { computed } from "vue";
const props = defineProps({ params: { type: Object, default: () => ({}) } });

const { data, api } = props.params;
const hierarchy = data.hierarchy;
const level = hierarchy.length - 1;

// 获取当前节点在表格中的行索引
const rowIndex = computed(() => api.getRowIndex(data));

// 判断当前节点是否是其父节点的最后一个子节点
const isLastNode = computed(() => {
  if (rowIndex.value === api.getDisplayedRowCount() - 1) return true;
  const nextRowData = api.getDisplayedRowAtIndex(rowIndex.value + 1).data;
  return nextRowData.hierarchy.length <= level;
});

// 判断指定层级是否为最后一个子节点(控制上层垂直连线)
const isLastChildAtLevel = (targetLevel) => {
  const currentPath = hierarchy.slice(0, targetLevel + 1);
  for (let i = rowIndex.value + 1; i < api.getDisplayedRowCount(); i++) {
    const rowData = api.getDisplayedRowAtIndex(i).data;
    const rowPath = rowData.hierarchy.slice(0, targetLevel + 1);
    if (JSON.stringify(rowPath) === JSON.stringify(currentPath)) return false;
    if (rowPath.length <= targetLevel) break;
  }
  return true;
};
</script>

修正后的Style

<style scoped>
.hierarchical-tree-cell {
  display: flex;
  align-items: center;
  height: 100%; /* 确保高度占满表格行 */
}

.level-indent {
  position: relative;
  width: 20px; /* 单个层级的缩进宽度 */
  height: 100%;
}

.node-prefix {
  position: relative;
  width: 20px;
  height: 100%;
}

.vertical-connector {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 9px; /* 垂直线居中 */
  width: 1px;
  background-color: #ccc;
}

/* 最后一个子节点的垂直连线只显示上半部分 */
.level-indent.last-child .vertical-connector {
  bottom: 50%;
}

.horizontal-connector {
  position: absolute;
  top: 50%;
  left: 0;
  right: 9px; /* 水平线到垂直线位置 */
  height: 1px;
  background-color: #ccc;
}

/* 最后一个节点的水平线只显示到中间 */
.node-prefix.last-child .horizontal-connector {
  right: 50%;
}

.tree-content {
  padding-left: 8px;
}
</style>

核心修改点

  1. 按层级拆分缩进:不再使用单一的缩进容器,为每个层级生成独立的缩进块,精准控制每个层级的连线显示。
  2. 最后子节点判断:通过对比当前节点与后续节点的层级和路径,确定是否为父节点的最后一个子节点,以此调整连线的显示范围。
  3. 样式精细化控制:利用CSS类切换,对最后一个子节点的连线进行截断,实现标准树形的连线效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:20:07