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

如何为Nebular NbTreeGridComponent实现分页及页面内容布局

我来帮你搞定Nebular NbTreeGridComponent的分页功能,同时确保表格之后能正常展示其他内容!因为NbTreeGrid本身没有内置分页,所以我们需要结合NbPaginationComponent来实现,下面分步骤给你详细说明:

1. 先搞定模板结构(Data Table组件)

首先在你的独立data-table组件模板里,按「树形表格 → 分页组件 → 后续内容」的顺序布局,这样就能保证表格之后的内容正常显示:

<!-- 树形表格核心 -->
<nb-tree-grid [data]="paginatedTreeData">
  <!-- 这里根据你的业务需求定义列,示例两列 -->
  <nb-tree-grid-column field="name" title="名称"></nb-tree-grid-column>
  <nb-tree-grid-column field="desc" title="描述"></nb-tree-grid-column>
  <!-- 其他列按需添加 -->
</nb-tree-grid>

<!-- 分页组件,绑定分页核心参数 -->
<nb-pagination
  [(page)]="currentPage"
  [pageSize]="pageSize"
  [total]="totalItems"
  (pageChange)="handlePageChange($event)"
  class="mt-3" <!-- 加个margin让分页和表格分开点 -->
></nb-pagination>

<!-- 表格之后要展示的其他内容 -->
<div class="post-table-section">
  <h4>表格后续内容区块</h4>
  <p>这里可以放任何你需要的内容:表单、统计卡片、其他组件都可以</p>
</div>

2. TypeScript逻辑实现分页

接下来处理分页的核心逻辑,这里分两种常见场景,你可以根据自己的业务需求选:

场景1:按顶层节点分页(简单易实现)

适合树形层级少、子节点数量不多的情况,分页只针对顶层节点,子节点展开后会跟随顶层节点显示在当前页:

import { Component, Input, OnInit } from '@angular/core';
import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme';

// 先定义你的树形数据结构接口
interface TreeItem {
  name: string;
  desc?: string;
  children?: TreeItem[];
  // 其他业务字段...
}

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.scss']
})
export class DataTableComponent implements OnInit {
  @Input() originalTreeData: TreeItem[]; // 父组件传入的原始树形数据
  paginatedTreeData: TreeItem[];
  dataSource: NbTreeGridDataSource<TreeItem>;

  // 分页基础配置,可根据需求调整
  currentPage = 1;
  pageSize = 10;
  totalItems = 0;

  constructor(private dataSourceBuilder: NbTreeGridDataSourceBuilder<TreeItem>) {}

  ngOnInit(): void {
    // 初始化总条目数(顶层节点数量)
    this.totalItems = this.originalTreeData.length;
    // 加载第一页数据
    this.updateTableData();
  }

  // 页码变化时触发
  handlePageChange(pageNum: number): void {
    this.currentPage = pageNum;
    this.updateTableData();
  }

  // 更新分页后的表格数据
  private updateTableData(): void {
    const startIdx = (this.currentPage - 1) * this.pageSize;
    const endIdx = startIdx + this.pageSize;
    // 对顶层节点数组进行切片,拿到当前页的顶层节点
    this.paginatedTreeData = this.originalTreeData.slice(startIdx, endIdx);
    // 更新表格数据源
    this.dataSource = this.dataSourceBuilder.create(this.paginatedTreeData);
  }
}

场景2:按所有可见行分页(复杂但精准)

如果需要把展开的子节点也纳入分页统计(比如一页显示10行,不管是顶层还是子节点),需要额外跟踪节点的展开状态,动态计算可见行:

// 继承上面的接口和基础代码,新增以下内容:

// 用节点唯一标识跟踪展开状态(建议给每个节点加id,这里用name示例,实际避免重复)
expandedNodeKeys = new Set<string>();

ngOnInit(): void {
  // 初始化时计算所有可见行数量
  this.totalItems = this.calcVisibleRowCount(this.originalTreeData);
  this.updateTableData();
}

// 计算当前展开状态下的可见行总数
private calcVisibleRowCount(nodes: TreeItem[]): number {
  let count = 0;
  nodes.forEach(node => {
    count++;
    // 如果节点展开且有子节点,递归计算子节点数量
    if (this.expandedNodeKeys.has(node.name) && node.children?.length) {
      count += this.calcVisibleRowCount(node.children);
    }
  });
  return count;
}

// 绑定表格的展开/折叠事件
onNodeExpand(node: TreeItem): void {
  this.expandedNodeKeys.add(node.name);
  this.totalItems = this.calcVisibleRowCount(this.originalTreeData);
  this.updateTableData();
}

onNodeCollapse(node: TreeItem): void {
  this.expandedNodeKeys.delete(node.name);
  this.totalItems = this.calcVisibleRowCount(this.originalTreeData);
  this.updateTableData();
}

// 更新分页数据,收集当前页的可见行
private updateTableData(): void {
  const visibleRows: TreeItem[] = [];
  const targetRowCount = this.currentPage * this.pageSize;
  // 递归收集可见行,直到达到目标数量
  this.collectVisibleRows(this.originalTreeData, visibleRows, targetRowCount);
  
  // 截取当前页的行范围
  const startIdx = (this.currentPage - 1) * this.pageSize;
  this.paginatedTreeData = visibleRows.slice(startIdx, targetRowCount);
  this.dataSource = this.dataSourceBuilder.create(this.paginatedTreeData);
}

// 递归收集可见行的工具方法
private collectVisibleRows(nodes: TreeItem[], result: TreeItem[], target: number): boolean {
  if (result.length >= target) return false;
  
  for (const node of nodes) {
    result.push(node);
    if (result.length >= target) return false;
    
    // 如果节点展开,继续收集子节点
    if (this.expandedNodeKeys.has(node.name) && node.children?.length) {
      const stop = this.collectVisibleRows(node.children, result, target);
      if (stop) return false;
    }
  }
  return true;
}

对应的模板需要添加展开/折叠事件绑定:

<nb-tree-grid 
  [data]="paginatedTreeData"
  (expand)="onNodeExpand($event.data)"
  (collapse)="onNodeCollapse($event.data)"
>
  <!-- 列定义不变 -->
</nb-tree-grid>

3. 父组件中使用Data Table

在需要引入表格的页面组件里,直接使用你的app-data-table并传入原始树形数据即可:

<app-data-table [originalTreeData]="yourBusinessTreeData"></app-data-table>
<!-- 父组件其他内容 -->

最后别忘了模块导入

确保你的模块(包括data-table模块和父页面模块)都导入了必要的Nebular模块:

import { NbTreeGridModule, NbPaginationModule } from '@nebular/theme';

@NgModule({
  imports: [
    // ...其他模块
    NbTreeGridModule,
    NbPaginationModule
  ]
})
export class YourModule { }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 22:22:47