更新Angular 5数据表时如何保持垂直滚动?

Posted

技术标签:

【中文标题】更新Angular 5数据表时如何保持垂直滚动?【英文标题】:How to maintain vertical scroll when updating Angular 5 data table? 【发布时间】:2018-09-21 01:19:50 【问题描述】:

我想使用从 JSON REST API 中提取的新数据经常更新我的数据表(Covalent td-data-table 和几个 ng-template)。多于浏览器的行数,因此用户可能需要垂直滚动。但是当我更新表中的数据时,它会完全重绘,即垂直滚动位置重置为顶部,工具提示闪烁等。

黑客攻击例如保存/恢复垂直滚动,例如以下类型的工作,但它们会造成很多视觉混乱,尤其是在 Firefox 中。

// save vertical scroll
this.scrollTop = this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop;

// update table data here
this.data = newData;

// restore vertical scroll
setImmediate(() => 
    this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop = this.scrollTop;
  
);

我怎样才能干净地更新表(或任何组件)中的数据,而无需修改滚动位置并忍受大量闪烁行为?

如果没有使用 Covalent 数据表的解决方案,是否有另一个 Angular 2+ 控件可以正确处理这个问题?

问题的动画屏幕截图:垂直滚动在数据更新时快速回退。应在数据更新期间保持垂直滚动。

【问题讨论】:

你好,我认为你需要 ngx-infinite-scroll ,它工作得很好,你可以使用 (scrolled) 来触发你请求并获取新数据并且你不会丢失你的滚动位置,这里是一个使用它的例子:echoesplayer.com/#/search/videos ngFor你应该使用列表,你使用trackBy函数吗?你是通过指数来做的吗?但你需要它给这个人。如果您将代码放在有问题的地方,它会更容易为您提供帮助。 @FatehMohamed 我不清楚如何将 ngx-infinite 与 td-data-table 一起使用。 @botika trackBy 听起来我们在正确的轨道上,但 td-data-table 没有 ngFor。我找不到任何方法将 trackBy 与 td-data-table 一起使用。 浏览光标后,<td-virtual-scroll-container [style.height.px]="400" [data]="data" [trackBy]="trackByFn"> ref covalent-nightly/virtual-scroll/ - 你能用虚拟卷轴包裹你的桌子吗? 【参考方案1】:

看起来当您获得更多数据时,您正在刷新整个列表(*ngFor 中使用的数组),因此 Angular 再次重新绘制完整表格。尝试仅将差异数据推送到该数组。

【讨论】:

1.-使用ViewChild获取“表”。 2.-在 ngDestroy 上(或在刷新表格之前)保存 naviteElement 在服务、localhost 或变量中滚动的位置。3.- 更新表格时使用此保存的变量 @Eliseo 这就是我粘贴的示例代码的作用。如前所述,它会产生大量闪烁和重绘,尤其是在 Firefox 中。【参考方案2】:

我建议你切换到角度材质并将其绑定到可观察的数据源。

https://material.angular.io/components/table/overview#observable-stream-of-data-arrays

当数据源(Observable)被新数据更新时,它会更新 DOM,并且不需要跟随滚动事件。

如果您担心页面上列出的项目的数量以简单的方式支持分页; . https://material.angular.io/components/table/overview#pagination

旁注:切换到有角度的材料,因为它们的组件都有很好的文档记录,包括示例和示例代码 让我知道,以防您遇到困难。

【讨论】:

角度材质数据表非常原始,最糟糕的是它不会将表头粘贴到位,当您滚动数据时它们会滚动!这是我需要 td-data-table 的主要原因之一,它可以在滚动数据时将表头固定到位。 解决了粘头问题。 github.com/angular/material2/issues/9143 使用建议的 CSS .mat-header-row position: sticky; position: -webkit-sticky; top: 0; background-color: inherit; 谢谢我没有意识到,这可能是一个前进的方向。如果可能的话,我仍然有几十个表我想避免重写,问题是关于 td-data-table 而不是 mat-table。 最后我采用了@stevebiko 的方法并切换到原生角度材料表。工作正常,仍然支持模板,粘性解决方法效果很好。我放弃了 td-data-table,从来没有让它满意。抱歉,赏金来得太晚了。【参考方案3】:

您可以尝试使用 trackBy 函数。此函数将用于确定 *ngFor 的哪些行已更改以优化重绘。

<tbody>
<tr td-data-table-row *ngFor="let row of basicData; trackBy: getRowId">
  <td td-data-table-cell *ngFor="let column of columns" [numeric]="column.numeric">
    column.format ? column.format(row[column.name]) : row[column.name]
  </td>
  <td td-data-table-cell (click)="openPrompt(row, 'comments')">
    <button mat-button [class.mat-accent]="!row['comments']">row['comments'] || 'Add Comment'</button>
  </td>
</tr>
</tbody>

然后在你的打字稿中:

getRowById(index, row) 
   // Return some unique primitive idenitifier (string, number, etc.)
   return row['some unique property'];

有关trackBy的更多信息,请查看:

https://netbasal.com/angular-2-improve-performance-with-trackby-cc147b5104e5 https://blog.angular-university.io/angular-2-ngfor/

此外,NGX-Datatable 非常适合这个用例。它内置了虚拟滚动。 https://github.com/swimlane/ngx-datatable

【讨论】:

我使用的是 td-data-table 而不是 ngx-datatable。 trackBy 可能是 ngx-datatable 的答案,但不清楚在哪里/如何使用 td-data-table。 另外@Pearman 您的代码使用 td-data-table-row/cell/etc。所述问题使用 td-data-table 和 ng-template,因此没有 *ngFor,因此没有 trackBy。 所以,是否有另一个 Angular 2+ 控件可以正确处理这个问题 - 这没关系,但 td-data-table 的正确语法不是好吗? 不确定你的意思@eric99。我很乐意使用 td-data-table-row/cell/etc。如上所示,但功能不等效。例如,没有粘性标题,没有 ng-templates,因此您不能将列混合和匹配到具有 hacking *ngIf 等的表中。但是 td-data-table 在使用垂直滚动时似乎变得平坦,因此目的的原始问题。【参考方案4】:

将数据推送到 *ngFor 正在使用的同一个数组变量不会重新渲染 html

简单示例:https://angular-frjdnf.stackblitz.io

编辑:

我使用 *ngFor 制作了一个带有共价表的示例项目,其中仅更新附加行而不重新渲染整个表。

链接到Stackblitz.io sample project。

HTML

<button (click)="addData()">Add Data</button>
<table td-data-table>
    <thead>
    <tr td-data-table-column-row>
      <td td-data-table-column *ngFor="let column of columns">
        column.label
      </td>
    </tr>
    </thead>
    <tbody>
    <tr td-data-table-row *ngFor="let row of basicData">
      <td td-data-table-cell *ngFor="let column of columns">
         row[column.name] 
      </td>
    </tr>
    </tbody>
  </table>

TS

basicData 具有加载到表中的初始数据,我只是在单击“添加数据”按钮时将一些虚拟数据推送到basicData,以测试滚动条。

import  Component  from '@angular/core';
import  ITdDataTableColumn  from '@covalent/core/data-table';

@Component(
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
)
export class AppComponent  
  columns: ITdDataTableColumn[] = [
     name: 'first_name',  label: 'First Name' ,
     name: 'last_name', label: 'Last Name' ,
     name: 'gender', label: 'Gender' 
  ];

  count = 0;

  basicData: any[] = [
    
      "first_name": "Sully",
      "gender": "Male",
      "last_name": "Clutterham"
    ,
    ...
  ]

  additionalData: any[] = [
    
      "first_name": "Sully",
      "gender": "Male",
      "last_name": "Clutterham"
    ,
    ...
  ]

  addData()
    if(this.count >= this.additionalData.length)
      this.count = 0;

    this.basicData.push(this.additionalData[this.count]);
    this.count++;
  


希望这会有所帮助。

【讨论】:

没有 *ngFor,见基本数据表代码 (teradata.github.io/covalent/#/components/data-table)。 从给定的演示页面,如果你检查“自定义数据表”演示代码,他们有&lt;table td-data-table&gt;...&lt;tr td-data-table-row *ngFor="let row of basicData"&gt;...&lt;/tr&gt;,他们正在将数据从 Json 文件传递​​到 basicData。我猜您正在遵循“基本数据表”演示结构,您只需要通过&lt;td-data-table&gt; 指令的输入装饰器 [data] 传递数据。您可以尝试使用“数据表(原子)组件”类型(如页面末尾所述)吗? 从“自定义数据表”代码部分,他们使用“数据表组件”,他们使用自定义属性,如td-data-table-rowtd-data-table-cell&lt;table td-data-table&gt; &lt;thead&gt; ... &lt;/thead&gt; &lt;tbody&gt; &lt;tr td-data-table-row *ngFor="let row of basicData"&gt; &lt;td td-data-table-cell *ngFor="let column of columns"&gt; row[column.name] &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; 我想使用原子组件,但是我失去了 td-data-table 的所有功能,例如自动粘页眉。问题专门针对具有 ng-template 子级的 td-data-table,而不是 td-data-table,td-data-table 是我工作所需要的。

以上是关于更新Angular 5数据表时如何保持垂直滚动?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 5 在每次路线点击时滚动到顶部

如何隐藏水平滚动条并保持垂直滚动条可见,同时仍然能够水平滚动?

Angular 5在显示mat-sidenav-container时停止背景滚动

如何制作 Bootstrap 下拉菜单的垂直滚动条

垂直滚动不适用于 HammerJS 和 Angular2

如何强制显示垂直滚动条? [复制]