Angular 8 CanDeactive路由守卫取消回退行为异常问题咨询
问题分析与解决方案
我之前也碰到过这个完全一样的问题!这背后的原因其实和浏览器历史栈的工作方式有关,跟Angular路由守卫的执行时机也脱不开干系:
问题根源
当你点击浏览器返回按钮时,浏览器会先修改自己的历史栈(把当前的PageThree从栈里移除,栈顶变成PageTwo),然后才触发Angular的路由守卫。当你在提示框点Cancel,守卫返回false阻止了导航,但此时浏览器的历史栈已经被修改了——它认为你现在应该在PageTwo,但实际页面还停留在PageThree。所以第二次点击返回时,浏览器会从PageTwo继续回退到PageOne,而不是你预期的从PageThree到PageTwo。
解决方案
我们需要在守卫阻止导航的时候,手动把当前页面重新添加回浏览器的历史栈里,这样就能修正历史记录的状态。修改你的PendingChangesGuard代码:
@Injectable() export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> { canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> { const canLeave = component.canDeactivate(); if (canLeave) { return true; } // 当用户选择取消离开时,修复历史栈 const confirmResult = confirm('Warning: You have unsaved changes. Press Cancel to go back or OK to lose these changes.'); if (!confirmResult) { // 把当前页面重新推入历史栈,修正浏览器的历史记录 window.history.pushState(null, null, window.location.href); } return confirmResult; } }
逻辑说明
当用户点击Cancel时,window.history.pushState()会把当前的PageThree URL重新加入历史栈,让浏览器的历史栈回到正确的状态(PageOne→PageTwo→PageThree)。这样第二次点击返回按钮时,浏览器会正常触发从PageThree到PageTwo的导航,守卫再次弹出提示,点击OK后就能正确回到PageTwo了。
适配Observable返回值的场景
如果你的组件canDeactivate方法返回的是Observable<boolean>,可以调整守卫代码来处理异步逻辑:
import { of, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> { canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> { const canLeave$ = typeof component.canDeactivate() === 'boolean' ? of(component.canDeactivate()) : component.canDeactivate(); return canLeave$.pipe( map(canLeave => { if (canLeave) { return true; } const confirmResult = confirm('Warning: You have unsaved changes. Press Cancel to go back or OK to lose these changes.'); if (!confirmResult) { window.history.pushState(null, null, window.location.href); } return confirmResult; }) ); } }
内容的提问来源于stack exchange,提问作者Chris Edgington
相关产品推荐
相关产品推荐

