Angular中*ngFor循环mat-card实现独立展开的问题解决
问题分析
你遇到的问题核心是用单个全局变量collapsed控制所有卡片的展开/折叠状态,所以操作任何一个卡片都会影响所有卡片的显示逻辑。要实现独立控制,必须给每个卡片分配单独的状态存储。
解决方案
1. 修改TS代码,为每个卡片维护独立状态
把原来的单个collapsed布尔值换成对象,用来存储每个卡片的展开状态,默认所有卡片处于折叠状态:
import { Component, OnInit } from '@angular/core'; import { trigger, state, style, transition, animate, AUTO_STYLE } from '@angular/animations'; import { Nutrition } from './NutritionData'; const DEFAULT_DURATION = 200; @Component({ selector: 'app-nutrition-report', templateUrl: './nutrition-report.component.html', styleUrls: ['./nutrition-report.component.scss'], animations: [ trigger('collapse', [ state('false', style({ height: AUTO_STYLE, visibility: AUTO_STYLE })), state('true', style({ height: '0', visibility: 'hidden' })), transition('false => true', animate(DEFAULT_DURATION + 'ms ease-in')), transition('true => false', animate(DEFAULT_DURATION + 'ms ease-out')), ]) ] }) export class NutritionReportComponent implements OnInit { Nutrition; // 用对象存储每个卡片的折叠状态,key为卡片索引,value为状态值 collapsedStates: {[key: number]: boolean} = {}; constructor() { this.Nutrition = Nutrition; } ngOnInit(): void { // 初始化所有卡片为折叠状态 this.Nutrition.forEach((_, index) => { this.collapsedStates[index] = true; }); } // 切换指定索引卡片的状态 toggle(index: number) { this.collapsedStates[index] = !this.collapsedStates[index]; } // 展开指定索引卡片 expand(index: number) { this.collapsedStates[index] = false; } // 折叠指定索引卡片 collapse(index: number) { this.collapsedStates[index] = true; } }
2. 修改HTML模板,绑定对应卡片的状态
去掉原来的*ngIf="i === index"判断,直接绑定当前卡片索引对应的状态,同时更新按钮的显示逻辑:
<h1 style="margin-top: 24px"> Report</h1> <mat-card class="mat-cards" *ngFor="let nutritionItem of Nutrition; let i = index"> <mat-card-header> <mat-card-title><h2>{{ nutritionItem.name }}</h2></mat-card-title> <mat-card-subtitle class="data">{{ nutritionItem.data }}</mat-card-subtitle> <mat-card-subtitle class="goal-range">{{ nutritionItem.goalRange }}</mat-card-subtitle> <div class="column1"> <mat-list role="list"> <mat-list-item role="listitem" class="first-item"> <h3 matLine class="previous">Previous Values</h3> <p class="prev" matLine style="font-size: 16px"> {{ nutritionItem.previousValue }} </p> <p class="prev" matLine style="font-size: 16px"> {{ nutritionItem.previousvalue1 }} </p> <p class="prev" matLine style="font-size: 16px"> {{ nutritionItem.previousvalue2 }} </p> </mat-list-item> </mat-list> </div> </mat-card-header> <div class="Content"> <mat-card-content> <!-- 绑定当前卡片的折叠状态,移除全局index判断 --> <div [@collapse]="collapsedStates[i]" class="expandable-content"> <div class="column2"> <mat-list role="list" class="table-column"> <mat-list-item role="listitem" class="first-item"> <h3 class="notes" matLine>{{ nutritionItem.notes }}</h3> <p class="description" matLine style="font-size: 16px"> {{ nutritionItem.Description }} </p> </mat-list-item> </mat-list> <mat-list role="list" class="table-column"> <mat-list-item role="listitem" class="first-item"> <h3 class="related" matLine>Content</h3> </mat-list-item> <ul> <li>{{nutritionItem.related}}</li> <li>{{nutritionItem.related1}}</li> </ul> </mat-list> </div> </div> </mat-card-content> <mat-divider></mat-divider> </div> <mat-card-actions> <!-- 根据当前卡片的状态显示对应按钮 --> <button *ngIf="collapsedStates[i]" (click)="expand(i)" class="mat-button">Expand</button> <button *ngIf="!collapsedStates[i]" (click)="collapse(i)" class="mat-button">Collapse</button> </mat-card-actions> </mat-card>
改动说明
- 用
collapsedStates对象替代单个collapsed变量,每个卡片索引对应独立的状态值,彻底解决状态联动问题。 - 在
ngOnInit中初始化所有卡片为折叠状态,确保页面加载时的初始状态统一。 - 模板中移除全局
index变量依赖,直接通过循环索引i获取对应卡片的状态,保证每个卡片只响应自身的状态变化。 - 修正循环变量名(
Nutrition改为nutritionItem),避免和数据源变量名冲突,提升代码可读性。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

