Angular 6中FileReader内Mat Snackbar显示异常及MatDialog自动关闭失效问题
哎,这俩问题我之前也碰到过!本质都是Angular变更检测周期的事儿,我给你捋清楚怎么解决:
1. Mat Snackbar 初始显示位置异常问题
这个问题的核心是 FileReader.onloadend 是浏览器原生的异步回调,它跑在Angular的变更检测周期之外。当你在这个回调里触发Snackbar时,Angular没意识到视图需要更新,所以初始渲染会跑偏到右侧,而点击屏幕会手动触发一次变更检测,这时候Snackbar才会乖乖跑到顶部。
解决办法很简单,用Angular的 NgZone 把Snackbar的调用包裹起来,强制让这个操作进入Angular的变更检测周期:
首先在组件里导入并注入 NgZone:
import { NgZone } from '@angular/core'; constructor(private _matSnackBar: MatSnackBar, private _ngZone: NgZone) {}
然后修改你的 showSnackBar 方法:
showSnackBar(message: string): void { this._ngZone.run(() => { this._matSnackBar.open(message, 'OK', { verticalPosition: 'top', duration: 2000, }); }); }
你也可以直接在 onloadend 的订阅回调里用 NgZone 包裹 showSnackBar 的调用,效果完全一样。
2. MatDialog 自动关闭失效问题
同样的坑!如果你的 setTimeout 是在原生回调、第三方库异步操作这类Angular变更检测周期外的地方调用的,就会出现“代码执行了但视图没反应”的情况——Dialog的关闭逻辑跑了,但Angular没检测到,直到你点击屏幕触发变更检测才会真正关闭。
解决思路和上面一致,用 NgZone 包裹关闭Dialog的操作:
假设你原来的代码是这样的:
openDialog() { const dialogRef = this._matDialog.open(YourDialogComponent); // 原来失效的自动关闭代码 setTimeout(() => { dialogRef.close(); }, 3000); }
修改成这样:
import { NgZone } from '@angular/core'; constructor(private _matDialog: MatDialog, private _ngZone: NgZone) {} openDialog() { const dialogRef = this._matDialog.open(YourDialogComponent); this._ngZone.run(() => { setTimeout(() => { dialogRef.close(); }, 3000); }); }
如果是在Dialog组件内部写的自动关闭逻辑,同样把 setTimeout 放到 NgZone.run() 里就行。要是还不行,你也可以手动触发变更检测——注入 ChangeDetectorRef,在 close() 之后调用 cdr.detectChanges(),不过优先用 NgZone 的方案更符合Angular的最佳实践。
内容的提问来源于stack exchange,提问作者madhu Goud

