Lzh on GitHub
<script setup lang="ts">
import { ref } from 'vue'
import {
  useVueTable,
  getCoreRowModel,
  getExpandedRowModel,
  createColumnHelper
} from '@tanstack/vue-table'

// 假设你的数据结构如下
type Item = {
  id: number
  name: string
  children?: Item[]
}

const data = ref<Item[]>([
  {
    id: 1,
    name: '父节点 A',
    children: [
      { id: 2, name: '子节点 A-1' },
      { id: 3, name: '子节点 A-2' }
    ]
  },
  {
    id: 4,
    name: '父节点 B',
    children: [
      { id: 5, name: '子节点 B-1' }
    ]
  }
])

const columnHelper = createColumnHelper<Item>()

const columns = [
  columnHelper.accessor('name', {
    header: '名称'
  }),
  // 你可以添加更多列
  columnHelper.accessor('id', {
    header: 'ID'
  })
]

const table = useVueTable({
  get data() { return data.value },
  columns,
  getSubRows: row => row.children,
  getCoreRowModel: getCoreRowModel(),
  getExpandedRowModel: getExpandedRowModel(),
  getRowCanExpand: row => !!row.original.children
})
</script>

<template>
  <div class="p-4">
    <table class="min-w-full divide-y divide-gray-200">
      <thead class="bg-gray-50">
        <tr
          v-for="headerGroup in table.getHeaderGroups()"
          :key="headerGroup.id"
        >
          <th
            v-for="header in headerGroup.headers"
            :key="header.id"
            class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
          >
            <div v-if="!header.isPlaceholder">
              {{ header.column.columnDef.header }}
            </div>
          </th>
        </tr>
      </thead>
      <tbody class="bg-white divide-y divide-gray-200">
        <tr
          v-for="row in table.getRowModel().rows"
          :key="row.id"
        >
          <td
            v-for="cell in row.getVisibleCells()"
            :key="cell.id"
            class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
          >
            <div
              v-if="cell.column.id === 'name'"
              class="flex items-center"
            >
              <button
                v-if="row.getCanExpand()"
                class="mr-2 text-sm"
                @click="row.getToggleExpandedHandler()()"
              >
                {{ row.getIsExpanded() ? '▼' : '▶' }}
              </button>
              <div
                v-else
                class="w-4 h-4 mr-2"
              />

              {{ cell.getValue() }}
            </div>
            <div v-else>
              {{ cell.getValue() }}
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>