You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 03:40:31