Angular mat-table点击单行播放按钮所有行按钮状态同步切换问题
问题原因
所有行播放按钮同步切换的核心问题是播放状态未和单行录音数据绑定:
- 服务层维护的
state是全局唯一的单例状态,整个表格所有行共用同一个state.playing字段做显示判断 - 模板内的按钮显示条件没有关联当前行的录音对象,只要全局状态为播放中,所有行都会统一判定为“正在播放”,渲染暂停按钮
修复方案
1. 修改表格模板,给按钮显示条件增加当前行数据校验
只给实际正在播放的对应行显示暂停按钮,其余行始终显示播放按钮:
<!-- audio display --> <ng-container matColumnDef="isPlaying"> <mat-header-cell *matHeaderCellDef>Playing</mat-header-cell> <mat-cell *matCellDef="let recording"> <button mat-button (click)="playToggle(recording)" [disabled]="state?.error" *ngIf="!(state?.playing && recording === currentPlayingRec)" > <mat-icon mat-list-icon>play_arrow</mat-icon> </button> <button mat-button (click)="pause()" *ngIf="state?.playing && recording === currentPlayingRec" > <mat-icon mat-list-icon>pause</mat-icon> </button> </mat-cell> </ng-container>
2. 修改组件类逻辑,明确维护当前播放的录音对象
把原来语义模糊的recording变量重命名为currentPlayingRec,补全播放切换、播放结束的状态重置逻辑:
export class RecordingsComponent implements OnInit { // ... 其余原有变量保留 // 替换原有的 recording: Recording; 变量 currentPlayingRec: Recording | null = null; // ... 其余原有生命周期、方法保留,只修改以下部分 ngOnInit(): void { this.currentUser = this._usersService.user; this.loadRecordings(); this._recordingsService.getState().subscribe(state => { this.state = state; // 音频自然播放结束时,清空当前播放记录 if (!state.playing && !state.error && state.currentTime === state.duration) { this.currentPlayingRec = null; } }); } playToggle(recording: Recording): void { // 点击当前正在播放的录音行,执行暂停 if (recording === this.currentPlayingRec) { this.pause(); this.currentPlayingRec = null; return; } // 切换新录音前先停止之前的播放 this.stop(); this.currentPlayingRec = recording; if (!this.currentPlayingRec?.url) { console.log('invalid recording resource'); return; } this.playStream(this.currentPlayingRec.url); } }
可选优化(非必须,解决潜在bug)
服务层的state是直接修改原对象属性再发射值,部分场景下会导致Angular变更检测不触发,可修改updateStateEvents方法,每次状态更新时发射新的对象副本:
private updateStateEvents(event: Event): void { // 基于原有状态创建新对象,避免引用问题导致变更检测失效 const newState = {...this.state}; switch (event.type) { case 'canplay': newState.duration = this.audioObj.duration; newState.readableDuration = this.formatTime(newState.duration); newState.canplay = true; break; case 'playing': newState.playing = true; break; case 'pause': newState.playing = false; break; case 'timeupdate': newState.currentTime = this.audioObj.currentTime; newState.readableCurrentTime = this.formatTime(newState.currentTime); break; case 'error': this.resetState(); this.state.error = true; this.stateChange.next({...this.state}); return; } this.state = newState; this.stateChange.next(newState); }
修复后效果:
播放状态下仅当前选中的录音行显示暂停按钮,其余行保持播放按钮显示,不会再出现全量同步切换的问题。
内容的提问来源于stack exchange,提问作者scott lucas
相关产品推荐
相关产品推荐

