Angular Mat如何实现打开其他Expansion Panel时关闭已开面板
问题原因
你现在的实现里每个交易条目都单独套了一个独立的<mat-accordion>实例,Angular Material默认的multi="false"互斥展开逻辑仅对同一个accordion标签内部的面板生效,跨独立accordion的面板状态完全不互通;再加上每个单条组件自己维护showHistory展开状态,组件之间没有任何通信,自然无法实现打开新面板自动关闭旧面板的效果。
另外你现在自定义的点击箭头切换showHistory的逻辑,和MatExpansionPanel自带的展开状态控制是冲突的,额外加的*ngIf="showHistory"也会破坏组件自带的展开动画和状态同步。
解决方案
方案1(推荐,改造成本最低)
把<mat-accordion>标签移到所有交易条目的外层父组件中,所有<mat-expansion-panel>都作为这个唯一accordion的子元素,不需要写任何自定义状态控制逻辑,原生就支持互斥展开:
- 父组件(循环渲染交易列表的组件)中放置唯一的
<mat-accordion>,默认multi="false"(不写配置默认就是这个值,自动开启互斥) - 在accordion内部通过
*ngFor循环渲染所有<mat-expansion-panel>,把你原来单条组件里的面板头、详情内容直接放到对应panel标签内 - 删除单条组件里自定义的
showHistory变量、fetchHistoryDetails点击事件、详情区的*ngIf="showHistory"控制,面板的展开收起完全交给Angular Material组件自身处理,需要加载详情的逻辑可以绑定面板的opened事件触发。
改完的父组件HTML示例:
<mat-accordion> <mat-expansion-panel *ngFor="let transactionDTO of transactionList" (opened)="fetchHistoryDetails(transactionDTO)"> <mat-expansion-panel-header> <div class="col text-center" [ngClass]="{ 'text-green': transactionDTO.txn_type == 'CREDIT', 'text-red': transactionDTO.txn_type == 'DEBIT', 'text-cyan': transactionDTO.txn_type == 'WITHDRAWAL' }" > {{ transactionDTO.txn_type }} </div> <div class="col text-center" style="font-size: 20px;"> {{ transactionDTO.created_date | date: "dd-MMM-yyyy" }} </div> <div class="text-center col-xl"> {{ transactionDTO.txn_status }} </div> <div class="col text-center" style="font-size: 20px;"> <span [ngClass]="{ 'text-green': transactionDTO.txn_type == 'CREDIT', 'text-red': transactionDTO.txn_type == 'DEBIT', 'text-cyan': transactionDTO.txn_type == 'WITHDRAWAL' }" ><ng-container *ngIf=" transactionDTO.txn_type == 'WITHDRAWAL' || transactionDTO.txn_type == 'DEBIT'; else credit " >-</ng-container ><ng-template #credit>+</ng-template >{{ transactionDTO.txn_amount | currency: "USD":"":"1.2-2" }}</span > </div> <div class="col text-center" style="font-size: 20px;"> {{ transactionDTO.final_amount | currency: "USD":"":"1.2-2" }} </div> <div class="col text-center downarrow"> {{ transactionDTO.payment_method == "Wire transfer" ? transactionDTO.txn_id : transactionDTO.payment_method }} </div> </mat-expansion-panel-header> <div class="row detailsRow no-gutters justofy-content-around align-items-center" marketplace-transaction-history-details [transactionType]="transactionDTO.transactionType" [userType]="'BUYER'" [currentStatusStep]="transactionDTO.currentStatus" ></div> </mat-expansion-panel> </mat-accordion>
原来的CSS里.mat-accordion .mat-expansion-panel:last-of-type的选择器去掉:last-of-type,不然只有最后一个面板会应用边框样式,其他面板样式会异常。
方案2(需要保留单条组件独立封装时使用)
如果必须保留单条组件独立包裹的结构,就通过父组件统一管理当前激活的面板ID,实现跨组件状态同步:
- 父组件维护变量
activePanelId: string | number = null,存储当前展开面板的唯一标识(用txn_id即可) - 给每个单条组件传入两个参数:当前条目的唯一ID、全局激活的
activePanelId,同时绑定单条组件抛出的面板切换事件 - 单条组件内通过计算属性判断自身是否应该展开,点击面板时把自身ID发射给父组件,父组件更新
activePanelId后,其他所有条目的状态会自动切换为收起。
内容的提问来源于stack exchange,提问作者user18643652
相关产品推荐
相关产品推荐

