如何编程式更改mat-button-toggle-group状态并拦截默认切换行为
问题背景
结合确认弹窗修改MatButtonToggleGroup状态时,无法直接阻止组件默认切换行为:MatButtonToggleChange事件未提供preventDefault()方法(组件底层实现了ControlValueAccessor接口),常规写法只能在用户点击弹窗取消按钮时,手动将状态重置为之前的旧值,容易出现UI闪烁。
初始问题代码
HTML 文件
<mat-button-toggle-group [value]="value" (change)="onChange($event)"> <mat-button-toggle [value]="StatusType.Open"> Open </mat-button-toggle> <mat-button-toggle [value]="StatusType.Closed"> Closed </mat-button-toggle> </mat-button-toggle-group>
TS 文件
@Input() value: StatusType; @Output() statusChange = new EventEmitter<StatusType>(); onChange(event: MatButtonToggleChange): void { const newValue = event.value; if (newValue === StatusType.Open) { this.statusChange.emit(value); return; } const dialogRef = this.dialog.open(ConfirmationDialogComponent, { data: { title: 'Confirm status change', message: 'Are you sure?', } }); dialogRef .afterClosed() .pipe( untilDestroyed(this), filter((result) => !!result) ) .subscribe(() => { this.statusChange.emit(newValue); }); }
实现方案
核心逻辑是放弃在change事件层做拦截,改为在click事件层提前阻止默认行为,用完全受控的绑定值控制组件选中状态,只有用户确认操作后才更新绑定值,从根源避免默认切换触发后再回滚的问题:
- 移除
mat-button-toggle-group上的(change)事件绑定,给每个mat-button-toggle单独绑定点击事件 - 点击事件触发时先调用
preventDefault()和stopPropagation()阻止组件默认的选中切换逻辑 - 仅当操作不需要确认、或用户点击确认弹窗的同意按钮时,才更新绑定的选中值,组件UI会自动和绑定值保持同步,不需要额外做重置操作
修改后代码
HTML 模板
<mat-button-toggle-group [value]="currentValue"> <mat-button-toggle [value]="StatusType.Open" (click)="onToggleClick($event, StatusType.Open)" > Open </mat-button-toggle> <mat-button-toggle [value]="StatusType.Closed" (click)="onToggleClick($event, StatusType.Closed)" > Closed </mat-button-toggle> </mat-button-toggle-group>
TS 逻辑
// 受控的当前选中值,替换原有直接绑定的输入值 currentValue: StatusType; @Input() set value(val: StatusType) { this.currentValue = val; } @Output() statusChange = new EventEmitter<StatusType>(); onToggleClick(event: MouseEvent, targetValue: StatusType): void { // 拦截默认切换行为 event.preventDefault(); event.stopPropagation(); // 点击项为当前已选中项,直接返回 if (targetValue === this.currentValue) return; // 切换到Open状态无需确认,直接更新 if (targetValue === StatusType.Open) { this.currentValue = targetValue; this.statusChange.emit(this.currentValue); return; } // 切换到Closed状态弹出确认框 const dialogRef = this.dialog.open(ConfirmationDialogComponent, { data: { title: 'Confirm status change', message: 'Are you sure?', } }); dialogRef.afterClosed() .pipe( untilDestroyed(this), filter(result => !!result) ) .subscribe(() => { // 仅确认后更新值,同步UI状态 this.currentValue = targetValue; this.statusChange.emit(this.currentValue); }); }
该实现不会出现先切换再回滚的UI闪烁问题,所有状态变更完全可控,不需要额外写取消后的状态重置逻辑。
内容的提问来源于stack exchange,提问作者Sergiu Molnar
相关产品推荐
相关产品推荐

