更新Angular5条数据table时如何保持垂直滚动?
How to maintain vertical scroll when updating Angular 5 data table?
我想经常使用从 JSON REST API.行数超出浏览器的容量,因此用户可能需要垂直滚动。但是当我更新 table 中的数据时,它会完全重绘,即垂直滚动位置重置到顶部,工具提示闪烁等。
黑客攻击,例如save/restore 像下面这样的垂直滚动效果很好,但它们会造成很多视觉混乱,尤其是在 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;
}
});
我如何才能干净地更新 table(或任何组件)中的数据,而无需重新设置滚动位置并忍受大量闪烁行为?
如果没有使用共价数据 table 的解决方案,是否有另一个 Angular 2+ 控件可以正确处理此问题?
问题的动画屏幕截图:更新数据时垂直滚动会弹回。应在数据更新期间保持垂直滚动。
看起来当你获得更多数据时,你正在刷新整个列表(*ngFor 中使用的数组)所以 angular 正在重新绘制完整 table。尝试仅将差异数据推送到该数组。
我建议您切换到 angular material 并将其绑定到可观察数据源。
https://material.angular.io/components/table/overview#observable-stream-of-data-arrays
当使用新数据更新数据源 (Observable) 时,它会更新 DOM 并且不需要关注滚动事件。
如果您担心页面上列出的项目数量,支持简单的分页; .
https://material.angular.io/components/table/overview#pagination
旁注:切换到 angular material,因为它们的组件有很好的文档记录,包括示例和示例代码
如果您遇到困难,请告诉我。
您可以尝试使用 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
将数据推送到 *ngFor 正在使用的同一数组变量不会重新呈现 html。
简单示例:https://angular-frjdnf.stackblitz.io
编辑:
我已经使用 *ngFor 和 angular 共价 table 制作了一个示例项目,仅更新附加行而不是重新渲染整个 table.
Link 到 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
具有加载到 table 中的初始数据,我只是在单击 "Add Data" 按钮时将一些虚拟数据推送到 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++;
}
}
希望对您有所帮助。
我想经常使用从 JSON REST API.行数超出浏览器的容量,因此用户可能需要垂直滚动。但是当我更新 table 中的数据时,它会完全重绘,即垂直滚动位置重置到顶部,工具提示闪烁等。
黑客攻击,例如save/restore 像下面这样的垂直滚动效果很好,但它们会造成很多视觉混乱,尤其是在 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;
}
});
我如何才能干净地更新 table(或任何组件)中的数据,而无需重新设置滚动位置并忍受大量闪烁行为?
如果没有使用共价数据 table 的解决方案,是否有另一个 Angular 2+ 控件可以正确处理此问题?
问题的动画屏幕截图:更新数据时垂直滚动会弹回。应在数据更新期间保持垂直滚动。
看起来当你获得更多数据时,你正在刷新整个列表(*ngFor 中使用的数组)所以 angular 正在重新绘制完整 table。尝试仅将差异数据推送到该数组。
我建议您切换到 angular material 并将其绑定到可观察数据源。
https://material.angular.io/components/table/overview#observable-stream-of-data-arrays
当使用新数据更新数据源 (Observable) 时,它会更新 DOM 并且不需要关注滚动事件。
如果您担心页面上列出的项目数量,支持简单的分页; . https://material.angular.io/components/table/overview#pagination
旁注:切换到 angular material,因为它们的组件有很好的文档记录,包括示例和示例代码 如果您遇到困难,请告诉我。
您可以尝试使用 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
将数据推送到 *ngFor 正在使用的同一数组变量不会重新呈现 html。
简单示例:https://angular-frjdnf.stackblitz.io
编辑:
我已经使用 *ngFor 和 angular 共价 table 制作了一个示例项目,仅更新附加行而不是重新渲染整个 table.
Link 到 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
具有加载到 table 中的初始数据,我只是在单击 "Add Data" 按钮时将一些虚拟数据推送到 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++;
}
}
希望对您有所帮助。