Angular中如何在HTML表格展示4列同属性且不重复数据?
解决Angular中Pokemon TCG API卡牌重复显示问题,实现每行4张不同卡牌布局
问题描述
在Angular系统中调用Pokemon TCG API,需要展示cards.images.small对应的卡牌图片,但当前表格实现导致每张卡牌重复显示4次,无法达成每行4张不同卡牌的布局。
现有代码
<div class="scroll"> <span class="font-extrabold text-3xl" style="color: #ffcb08;" *ngIf="spinner">Carregando cartas</span> <table *ngIf="!spinner" mat-table [dataSource]="dataSource" class="mat-elevation-z8 mat-table"> <ng-container matColumnDef="position"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(element)" mat-cell *matCellDef="let element"> <img class="card" [src]="element.images?.small" alt=""> </td> </ng-container> <ng-container matColumnDef="position2"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(element)" mat-cell *matCellDef="let element"> <img class="card" [src]="element.images?.small" alt=""> </td> </ng-container> <ng-container matColumnDef="position3"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(element)" mat-cell *matCellDef="let element"> <img class="card" [src]="element.images?.small" alt=""> </td> </ng-container> <ng-container matColumnDef="position4"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(element)" mat-cell *matCellDef="let element"> <img class="card" [src]="element.images?.small" alt=""> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> </div>
问题原因
当前Mat Table的实现逻辑是将单条卡牌数据渲染到4列中,每一列都绑定了同一个element对象,导致每行的4列显示同一张卡牌。
修复方案
方案1:使用CSS Grid + *ngFor(推荐)
这种方式无需修改数据源结构,通过CSS直接控制网格布局,代码更简洁:
模板代码
<div class="scroll"> <span class="font-extrabold text-3xl" style="color: #ffcb08;" *ngIf="spinner">加载卡牌中</span> <div *ngIf="!spinner" class="card-grid"> <div (click)="addCard(card)" class="card-item" *ngFor="let card of dataSource"> <img class="card" [src]="card.images?.small" alt="宝可梦卡牌"> </div> </div> </div>
CSS样式
.card-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; padding: 1rem; } .card-item { cursor: pointer; } .card { width: 100%; height: auto; }
方案2:改造Mat Table数据源(若必须使用Mat Table)
先在组件中将一维卡牌数组转换为每行4张的二维数组:
组件类代码
transformDataSource(): void { const chunkSize = 4; this.transformedDataSource = []; for (let i = 0; i < this.dataSource.length; i += chunkSize) { this.transformedDataSource.push(this.dataSource.slice(i, i + chunkSize)); } } // 在API数据加载完成后调用转换方法 this.pokemonApiService.getCards().subscribe(cards => { this.dataSource = cards; this.transformDataSource(); this.spinner = false; });
修改后的模板代码
<div class="scroll"> <span class="font-extrabold text-3xl" style="color: #ffcb08;" *ngIf="spinner">加载卡牌中</span> <table *ngIf="!spinner" mat-table [dataSource]="transformedDataSource" class="mat-elevation-z8 mat-table"> <ng-container matColumnDef="col1"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(row[0])" mat-cell *matCellDef="let row"> <img *ngIf="row[0]" class="card" [src]="row[0].images?.small" alt="宝可梦卡牌"> </td> </ng-container> <ng-container matColumnDef="col2"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(row[1])" mat-cell *matCellDef="let row"> <img *ngIf="row[1]" class="card" [src]="row[1].images?.small" alt="宝可梦卡牌"> </td> </ng-container> <ng-container matColumnDef="col3"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(row[2])" mat-cell *matCellDef="let row"> <img *ngIf="row[2]" class="card" [src]="row[2].images?.small" alt="宝可梦卡牌"> </td> </ng-container> <ng-container matColumnDef="col4"> <th mat-header-cell *matHeaderCellDef></th> <td (click)="addCard(row[3])" mat-cell *matCellDef="let row"> <img *ngIf="row[3]" class="card" [src]="row[3].images?.small" alt="宝可梦卡牌"> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="['col1', 'col2', 'col3', 'col4']"></tr> <tr mat-row *matRowDef="let row; columns: ['col1', 'col2', 'col3', 'col4'];"></tr> </table> </div>
内容的提问来源于stack exchange,提问作者Humberto Constantino
相关产品推荐
相关产品推荐

