Ember 3.16中resetController函数transition有时未定义的原因
resetController的transition参数偶尔为undefined的原因分析 结合Ember 3.16的路由机制,以下是几种可能导致该问题的场景:
1. 浏览器历史导航触发的路由切换
当通过浏览器的前进、后退按钮触发路由跳转时,属于popstate事件驱动的历史操作,并非Ember主动发起的transitionTo/replaceWith过渡。在这类场景下,resetController方法接收的transition参数会是undefined——因为没有生成对应的Ember过渡对象。如果你的测试流程中包含这类操作,就会出现参数缺失的情况。
2. 路由过渡被隐性中止
如果在离开路由x的过程中,某个路由钩子(如beforeModel、model)内部调用了transition.abort()中止过渡,后续触发的resetController可能丢失transition参数。即使路由最终完成了切换,部分隐性的中止逻辑(比如错误捕获后的中止操作)也可能导致这种情况。
3. 使用replaceWith覆盖历史记录
当使用replaceWith方法跳转到目标路由时,当前路由的历史记录会被新路由覆盖。在Ember 3.16的部分场景下,这种过渡的transition参数不会被正确传递到resetController中,因为过渡没有保留完整的历史轨迹。
4. 手动销毁路由实例
如果应用中存在手动调用disconnectOutlet销毁路由对应控制器或组件的逻辑,此时触发的resetController不会携带transition参数——因为这种销毁操作并非由路由过渡触发,而是手动执行的资源清理。
针对需求的优化方案
既然你需要每次离开路由x后返回时都重置控制器,建议调整判断逻辑,减少对transition参数的依赖:
方案1:通过路由名称判断是否为内部刷新
resetController(controller, isExiting) { if (isExiting) { // 判断是否是路由内部刷新(如分页切换) const targetRoute = this.router.currentRouteName; const isInternalRefresh = targetRoute === this.routeName; if (!isInternalRefresh) { // 执行你的重置逻辑 // ... } } }
方案2:结合willTransition钩子标记离开状态
willTransition(transition) { // 标记是否是离开到其他路由 this.set('isLeavingToExternal', transition.targetName !== this.routeName); return true; }, resetController(controller, isExiting) { if (isExiting && this.get('isLeavingToExternal')) { // 执行重置逻辑 // ... // 重置标记 this.set('isLeavingToExternal', false); } }
这两种方案都能避免因transition参数缺失导致的重置失效,同时排除分页切换这类内部刷新场景。
内容的提问来源于stack exchange,提问作者Abdul Wadood

