
大家好! 我的名字叫KitApp的程序员Nikita Zhigamovsky,我想谈谈我在Ionic 4中构建导航的经验:我遇到的问题及其解决方案。
自2018年以来,我一直在为移动应用程序开发跨平台解决方案。 我曾经使用过Ionic 3rd版本,但是随着时间的流逝,功能不断发展,我决定切换到新版本,并且Ionic 4中以前型号的烦人的时刻和错误
似乎已经得到解决。
看来可能出问题了。 最后,我们具有正常Angular路由的功能,而不是具有所有缺点的旧版NavController。 即使在Ionic的官方网站上,路由指南也显示使用
Angular / Router方法以编程方式浏览页面是值得的。 但是有些事情使我回到了旧的NavController。
问题的实质
注意到一个有趣的错误。 假设您有一个侧面菜单,则使用离子分离窗格来完成。 另外,您从菜单中有单独的页面,并且想要从它们转到菜单中的其他页面。 使用Router.navigateByUrl('/ menu / ...')进行导航。 接下来,我们将菜单页面称为A,将菜单页面与菜单B分开。但是这里有一个
!假设在A页上,在ngOnInit事件中触发了某种逻辑。 您使用路由器导航到页面B,并注意到菜单页面仍处于活动状态-尚未删除。 因此,如果您返回到页面A,则ngOnInit事件将不起作用,因为此页面的ngOnDestroy事件不起作用。 似乎一切都是合乎逻辑的。 在这种情况下,它们通常采用一种生命周期方法,而不是角度方法,而是离子方法-ionViewWillEnter。 当该页面变为活动状态时,它将触发。 一切似乎都很好,很合适,但是有一定的约定。
如果此转换不是来自菜单中的页面,则转到A页上的适当操作的所有选项均不起作用。 您将无法跟踪到该页面的过渡,因为我重复说,它仍然处于打开状态,并且在其他页面(例如,B页面)下可以安静地运行。
一些说明性示例:
如果您具有以下页面结构,ionViewWillEnter将起作用:
1)分页
-第1页
-第2页
-第3页在此示例中,当我转到每个页面时,ionViewWillEnter会完美运行。 (第1页=>第2页,第2页=>第3页,依此类推)
2)菜单/标签
-菜单
-menuPage1
-menuPage2
-menuPage3在此示例中,一切也将正常:每次访问任何页面(menuPage1 => menuPage2,menuPage1 => menuPage3等)时,ionViewWillEnter方法都会触发。
但是在下面的示例中,一切都变得更加复杂:
-菜单
-menuPage1
-menuPage2
-menuPage3
-登录页面
-signupPage这是标准角度布线问题的起点。 在菜单页面内导航时(menuPage1 => menuPage2 => menuPage3)-ionViewWillEnter方法将照常工作,就像在各个页面之间导航时一样(loginPage => signupPage)。 但是,一旦我们开始在单独的页面和菜单页面之间切换(loginPage => menu / menuPage1或menu / menuPage3 => signupPage),ngOnInit方法和ionViewWillEnter都不起作用。 ngOnInit将不起作用,因为该页面尚未被破坏,这是合乎逻辑的。 但是为什么ionViewWillEnter无法工作?
根据文档,ionViewWillEnter在单独的路由堆栈(关键字“ individual”)中或在各个页面之间,或在菜单/选项卡中起作用。 但不是单个页面和菜单/选项卡的混合结构。 奇怪,但这被认为是正常行为。 同时,这也不是用户期望的行为,尤其是当您考虑生命周期挂钩的名称时:)。
那么如何解决这个问题呢?
曾经访问过许多论坛,但没有看到正常的解决方案,并且看到了一些并不总是有效的可疑生活技巧,因此很明显,还需要其他一些技巧。 会改变任何类型页面之间转换功能的东西。
在这种情况下该怎么办? 当然,将Router丢到地狱而忘却它,因为仍然有我们以前讨厌的,现在是如此出色的NavController。
NavController.navigateRoot()方法之间的主要区别在于,切换到另一页后,上一页会自动销毁! 当您再次切换到它时,ngOnInit方法和ionViewWillEnter都将起作用! 实际上-这是一个完美的解决方案-没有拐杖和可疑的自写功能。
最酷的是,它可以与任何页面结构一起使用:就像上一个示例一样,即使在普通页面之间,菜单内部甚至混合类型之间也可以使用。
总结积极方面:
- 返回目录时,NavController分别从堆栈中删除前一页-更新后,ionViewWillEnter和ngOnInit方法起作用,例如,您可以再次调用其中的逻辑并更新页面上的信息。
- 忘记旧的push(),setRoot()和pop()方法,以及在类元素中导航。 毕竟,正是这造成了许多问题。 现在,navCtrl已更新了方法,这些方法的传递路径与Router方法中的路径相同。
有一个警告,没有“ BUT”的地方就不要:)
如果在Android设备上的硬件“后退”按钮上添加事件处理程序,然后在该处理程序中尝试使用Router或navController到某个地方,则在控制台中将出现以下错误:“在Angular区域之外触发了导航”。
是的,导航将起作用,页面将打开,但是对它没有任何作用-属性初始化或生命周期方法均无效。 不幸的是,按下返回按钮的导航是在Angular区域之外触发的,实际上,它仅打开模板:没有将变量绑定到模板,没有函数,钩子,生命周期方法-没有任何东西。
实际上,解决方案非常简单。 我们只是明确地在Angular区域内强制导航。
一个例子:import { Component, NgZone } from '@angular/core'; import { NavController } from '@ionic/angular'; @Component({ selector: 'app-root', templateUrl: 'app.component.html' }) export class AppComponent { constructor(private navCtrl: NavController, private ngZone: NgZone){} this.ngZone.run(() => this.navCtrl.navigateForward('menu')).then(); this.ngZone.run(() => this.router.navigateByUrl('/menu/my-orders')).then(); }
现在一切正常!
关于ngZone有很多有趣的文章,我建议您阅读。 祝你好运!
关于navController的方法:
- this.navCtrl.setDirection('root')-设置堆栈上的根页面,删除所有先前的页面。
- this.navCtrl.navigateRoot('homePage')-类似于navCtrl.setDirection('root')+ router.navigateByUrl('homePage'),但必须删除堆栈中的前一页(这是我们需要的)。
- this.navCtrl.navigateForward('examplePage')-与router.navigateByUrl('/ examplePage)类似,但是明确指示要去的地方+可以删除堆栈中的上一页。
- this.navCtrl.back()-与location.back()类似,但带有动画。
- this.navCtrl.navigateBack('backPage')-类似于navCtrl.setDirection('back')+ router.navigateByUrl('backPage')。
假设我们现在位于菜单/第1页上,

我们有一个单独的菜单堆栈,从menu / page1到登录页面后,我们需要删除menu / page1页面,以便在再次切换到它之后,我们将对ngOnInit或ionViewWillEnter使用某种逻辑。 如果我们使用router.navigateByUrl('login)进行过渡,那么在此之后,我们将位于登录页面上,但我们还将拥有一个菜单页面,

因此,从登录名切换到菜单/ page1后,ngOnInit和ionViewWillEnter均不起作用。
如果您使用我们的navCtrl.navigateRoot('login')进行导航,则在打开登录页面后,将删除上一页。 ngOnInit和ionViewWillEnter方法将起作用。

这是使用navController的好处-
预期的行为与当前行为完全一致 。