我在 Ng-zorro 的 Angular 项目中使用 cdk 虚拟滚动。我有一个折叠组件列表,在该列表中是我使用虚拟滚动的地方。
问题是当我打开一个折叠时,如果内容大于窗口高度,当我滚动另一个折叠时打开。
我认为它会发生,因为当虚拟滚动加载更多内容时,它会为每个折叠组件提供一个 id,每次滚动时都会更改。但这是一个模糊的想法,我没有找到相关信息。
这是我的 hmtl 列表文件:
<div class="fair">
<h3>{{exhibition.toString()}}</h3>
</div>
<nz-radio-group class="radio-buttons" [(ngModel)]="userStats" [hidden]="!isAdmin && !isManager">
<label nz-radio-button [nzValue]="true" (click)="clickedMyVisits()">My Visits</label>
<label nz-radio-button [nzValue]="false" (click)="clickedAllVisits()">All Visits</label>
</nz-radio-group>
<cdk-virtual-scroll-viewport appendOnly itemSize="41">
<app-visit-info
*cdkVirtualFor="let visit of visitDataSource"
[visit]="visit"
[showUsername]="isAdmin || isManager"
[username]="this.username.toUpperCase()">
</app-visit-info>
</cdk-virtual-scroll-viewport>
<ng-template #loading>
<nz-spin nzTip="Loading..." class="spin"></nz-spin>
</ng-template>
<ng-template #empty>
<nz-empty class="empty"></nz-empty>
</ng-template>
这是我的折叠组件:
<nz-collapse>
<nz-collapse-panel [nzHeader]="showUsername ? visit.toPanelUserString() : visit.toPanelString()">
<div *ngIf="visit; else loading">
<div class="title">
<h2>{{visit.name}}</h2>
<h2 *ngIf="visit.visitType">{{visit.visitType?.description}}</h2>
<h2>{{visit.systemDate | date: "dd/MM/yyyy HH:mm"}}</h2>
</div>
</div>
</nz-collapse-panel>
</nz-collapse>
这是我的 ts 文件:
@Component({
selector: 'app-visit-list',
templateUrl: './visit-list.component.html',
styleUrls: ['./visit-list.component.less'],
})
export class VisitListComponent implements OnInit, OnDestroy {
visits$!: Observable<Visit[]>;
user$!: Observable<User>;
companyCode!: string;
username!: string;
exhibitionCode!: string;
exhibition!: Exhibition;
userStats = true;
visitQuery: VisitQuery = {};
visitDataSource!: VisitDataSource;
isAdmin!: boolean;
isManager!: boolean;
subscriptions$: Subscription[] = [];
constructor(private visitService: VisitService,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private store: Store) {
this.visitDataSource = new VisitDataSource(this.visitService, this.visitQuery, this.companyCode);
}
ngOnDestroy(): void {
this.subscriptions$.forEach(sub => sub.unsubscribe());
}
ngOnInit(): void {
this.subscriptions$.push(this.store.select(state => state.companyCode.companyCode).subscribe(
companyCode => {
this.companyCode = companyCode;
this.loadData();
}
));
}
loadData(){
this.username = this.activatedRoute.snapshot.paramMap.get('username')!;
this.companyCode = this.activatedRoute.snapshot.paramMap.get('companyCode')!;
this.exhibitionCode = this.activatedRoute.snapshot.paramMap.get('exhibitionCode')!;
this.exhibition = GlobalExhibition.exhibition;
this.isAdmin = this.authService.hasAdminRole();
this.isManager = this.authService.hasManagernRole();
this.visitQuery = {
username: this.username,
exhibitionCode: this.exhibitionCode,
visitUsername: this.username
}
this.clickedMyVisits();
}
clickedAllVisits() {
this.visitQuery = {
username: this.username,
exhibitionCode: this.exhibitionCode,
}
this.visitDataSource = new VisitDataSource(this.visitService, this.visitQuery, this.companyCode);
}
clickedMyVisits() {
this.visitQuery = {
username: this.username,
exhibitionCode: this.exhibitionCode,
visitUsername: this.username
}
this.visitDataSource = new VisitDataSource(this.visitService, this.visitQuery, this.companyCode);
}
}
class VisitDataSource extends DataSource<Visit> {
public itemsInMemory = Array.from<Visit>({length: 0});
private itemChanges$: BehaviorSubject<Visit[]> = new BehaviorSubject<Visit[]>([]);
private destroy$: Subject<boolean> = new Subject();
private pageSize = 25;
private lastLoadedPage = 0;
constructor(private visitService: VisitService,
private visitQuery: VisitQuery,
private companyCode: string){
super();
visitQuery.pageSize = this.pageSize;
this.itemChanges$ = new BehaviorSubject(this.itemsInMemory);
this.getInformation();
}
connect(collectionViewer: CollectionViewer){
collectionViewer.viewChange.pipe(takeUntil(this.destroy$)).subscribe(range => {
const currentPage = Math.floor(range.end / this.pageSize);
if(currentPage > this.lastLoadedPage){
this.lastLoadedPage = currentPage;
this.getInformation();
}
});
return this.itemChanges$;
}
getInformation(){
this.visitQuery.offset = this.lastLoadedPage * this.pageSize;
this.visitQuery.companyCode = this.companyCode;
if(this.visitQuery.exhibitionCode){
this.visitService.findVisitsPagination(this.visitQuery).subscribe(data =>{
data.forEach(visit => {
this.itemsInMemory.push(visit);
this.itemChanges$.next(this.itemsInMemory);
})
});
}
}
disconnect(){
this.destroy$.next(true);
this.destroy$.complete();
}
}
谢谢大家!<3