
Hallo allerseits! Mein Name ist Nikita Zhigamovsky, ein Programmierer bei
KitApp, und ich möchte über meine Erfahrungen beim
Erstellen der Navigation in Ionic 4 sprechen: das Problem, auf das ich gestoßen bin, und seine Lösung.
Seit 2018 entwickle ich plattformübergreifende Lösungen für mobile Anwendungen. Früher habe ich an der 3. Version von Ionic gearbeitet, aber im Laufe der Zeit entwickelt sich die Funktionalität weiter. Ich habe mich für eine neuere Version entschieden, und die nervigen Momente und Fehler des Vorgängermodells in Ionic 4
scheinen bereits behoben zu sein.
Es scheint, dass was schief gehen könnte. Schließlich haben wir die Funktionalität eines normalen Angular-Routings und nicht den alten NavController mit all seinen Mängeln. Selbst auf der offiziellen Ionic-Website wird im Routing-Handbuch darauf hingewiesen, dass sich das programmgesteuerte Navigieren durch Seiten mithilfe der
Winkel- / Routermethoden lohnt. Aber es gab etwas, das mich dazu brachte, zum alten NavController zurückzukehren.
Das Wesentliche des Problems
Ein interessanter Fehler wurde bemerkt. Angenommen, Sie haben ein Seitenmenü, das Sie mit dem Ionensplit-Bereich erstellt haben. Sie haben auch separate Seiten aus dem Menü und möchten von diesen zu anderen Seiten im Menü wechseln. Navigieren Sie mit Router.navigateByUrl ('/ menu / ...'). Als nächstes nennen wir die Menüseite A und die vom Menü getrennte Seite - B. Aber es gibt eine
ABER!Angenommen, auf Seite A wird im ngOnInit-Ereignis eine bestimmte Logik ausgelöst. Sie navigieren mit dem Router zu Seite B und stellen fest, dass die Menüseite noch aktiv ist - sie wurde nicht gelöscht. Wenn Sie zu Seite A zurückkehren, funktioniert das ngOnInit-Ereignis nicht, da das ngOnDestroy-Ereignis dieser Seite nicht funktioniert hat. Es scheint, dass alles logisch ist. In solchen Momenten greifen sie normalerweise auf eine der Lebenszyklusmethoden zurück, nicht auf die Winkelmethode, sondern auf die ionische - ionViewWillEnter. Es wird ausgelöst, wenn Sie zur Seite gehen, sobald sie aktiv wird. Alles scheint in Ordnung zu sein, es passt perfekt, aber es gibt eine bestimmte Anzahl von Konventionen.
Keine der Optionen für eine angemessene Aktion auf Seite A funktioniert, wenn dieser Übergang nicht von Seiten erfolgt, die sich im Menü befinden. Sie können den Übergang zu dieser Seite nicht verfolgen, da sie, wie ich wiederhole, noch geöffnet ist und unter anderen Seiten, z. B. unter Seite B, leise funktioniert.
Einige anschauliche Beispiele:
ionViewWillEnter funktioniert, wenn Sie die folgende Seitenstruktur haben:
1) Separate Seiten
- Seite1
- Seite2
- Seite3In diesem Beispiel funktioniert ionViewWillEnter einwandfrei, wenn ich zu jeder Seite gehe. (Seite1 => Seite2, Seite2 => Seite3 usw.)
2) Menü / Registerkarten
- Menü
- menuPage1
- menuPage2
- menuPage3In diesem Beispiel ist auch alles in Ordnung: Die ionViewWillEnter-Methode wird jedes Mal ausgelöst, wenn Sie eine der Seiten aufrufen (menuPage1 => menuPage2, menuPage1 => menuPage3 usw.).
Im folgenden Beispiel ist jedoch alles komplizierter:
- Menü
- menuPage1
- menuPage2
- menuPage3
- loginPage
- signupPageHier beginnen die Probleme des Standard-Angular-Routings. Beim Navigieren innerhalb von Menüseiten (menuPage1 => menuPage2 => menuPage3) funktioniert die ionViewWillEnter-Methode wie gewohnt beim Navigieren zwischen einzelnen Seiten (loginPage => signupPage). Sobald wir jedoch zwischen getrennten Seiten und Menüseiten wechseln (loginPage => menu / menuPage1 oder menu / menuPage3 => signupPage), funktionieren weder die ngOnInit-Methode noch ionViewWillEnter. ngOnInit funktioniert nicht, da die Seite nicht zerstört wurde, was logisch ist. Aber warum hat ionViewWillEnter nicht funktioniert?
Basierend auf der Dokumentation arbeitet ionViewWillEnter in separaten Routing-Stacks (das Schlüsselwort „individual“) oder zwischen einzelnen Seiten oder in Menüs / Registerkarten. Aber nicht in der gemischten Struktur einzelner Seiten und Menüs / Registerkarten. Seltsam, aber dies wird als normales Verhalten angesehen. Gleichzeitig ist dies nicht genau das Verhalten, das Benutzer erwarten, insbesondere wenn Sie den Namen der Lifecycle-Hooks berücksichtigen :).
Wie kann man dieses Problem lösen?
Nachdem ich viele Foren besucht habe, aber keine normale Lösung gesehen habe und einige zweifelhafte Life-Hacks gesehen habe, die nicht immer funktionieren, wird klar, dass etwas anderes benötigt wird. Etwas, das die Übergangsfunktionalität zwischen Seiten eines beliebigen Typs ändert.
Was ist in diesem Fall zu tun? Werfen Sie den Router natürlich in die Hölle und vergessen Sie ihn, denn es gibt immer noch unseren zuvor gehassten und jetzt so guten NavController.
Der Hauptunterschied zwischen der NavController.navigateRoot () -Methode besteht darin, dass nach dem Wechsel zu einer anderen Seite die vorherige automatisch zerstört wird! Und wenn Sie erneut darauf umschalten, funktionieren sowohl die ngOnInit-Methode als auch ionViewWillEnter! In der Tat - dies ist die perfekte Lösung - ohne Krücken und zweifelhafte selbstgeschriebene Funktionen.
Das Coolste ist, dass es mit jeder Seitenstruktur funktioniert: sogar zwischen normalem, sogar innerhalb des Menüs, sogar gemischtem Typ, wie im letzten Beispiel.
Fassen Sie die positiven Aspekte zusammen:
- NavController löscht die vorherige Seite jeweils aus dem Stapel, wenn Sie dorthin zurückkehren. Sie wird aktualisiert, die Methoden ionViewWillEnter und ngOnInit funktionieren, und Sie können die darin enthaltene Logik erneut aufrufen und beispielsweise die Informationen auf den Seiten aktualisieren.
- Vergessen Sie die alten Methoden push (), setRoot () und pop () und navigieren Sie durch Klassenelemente. Immerhin hat dies viele Probleme verursacht. Jetzt hat navCtrl Methoden aktualisiert, denen derselbe Pfad wie in den Methoden des Routers übergeben wird.
Es gibt eine Einschränkung, wo auf "ABER" verzichten :)
Wenn wir der Hardware-Schaltfläche "Zurück" auf dem Android einen Ereignishandler hinzufügen und in diesem Handler versuchen, mit Router oder navController irgendwohin zu gelangen, wird in der Konsole der folgende Fehler angezeigt: "Navigation außerhalb der Winkelzone ausgelöst".
Ja, die Navigation funktioniert, die Seite wird geöffnet, aber es funktioniert nichts - weder die Initialisierung von Eigenschaften noch die Lebenszyklusmethoden. Leider wird die Navigation durch Drücken der Zurück-Taste außerhalb der Winkelzone ausgelöst und öffnet tatsächlich nur die Vorlage: ohne Variablen an die Vorlage zu binden, ohne Funktionen, Hooks, Lebenszyklusmethoden - ohne irgendetwas.
Die Lösung ist eigentlich sehr einfach. Wir erzwingen einfach explizit die Navigation innerhalb der Winkelzone.
Ein Beispiel: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(); }
Und jetzt funktioniert alles gut!
Es gibt viele interessante Artikel über ngZone, ich rate Ihnen zu lesen. Viel Glück!
Ein bisschen über die Methoden von navController:
- this.navCtrl.setDirection ('root') - Legt die Stammseite auf dem Stapel fest und löscht alle vorherigen.
- this.navCtrl.navigateRoot ('homePage') - ähnlich wie navCtrl.setDirection ('root') + router.navigateByUrl ('homePage'), jedoch mit dem obligatorischen Entfernen der vorherigen Seite auf dem Stapel (was wir brauchen).
- this.navCtrl.navigateForward ('examplePage') - ähnlich wie router.navigateByUrl ('/ examplePage), jedoch mit einer expliziten Angabe, wohin + die vorherige Seite auf dem Stapel gelöscht werden kann.
- this.navCtrl.back () - ähnlich wie location.back (), jedoch mit Animation.
- this.navCtrl.navigateBack ('backPage') - ähnlich wie navCtrl.setDirection ('back') + router.navigateByUrl ('backPage').
Angenommen, wir befinden uns jetzt auf Menü / Seite 1.

und wir haben einen separaten Menüstapel und nachdem wir von Menü / Seite1 zur Anmeldeseite gewechselt sind, müssen wir die Seite Menü / Seite1 löschen, damit nach dem erneuten Wechseln eine Art Logik auf ngOnInit oder ionViewWillEnter funktioniert. Wenn wir router.navigateByUrl ('login) für den Übergang verwenden, befinden wir uns danach auf der Anmeldeseite, aber wir haben auch eine Menüseite.

Dementsprechend funktionieren nach dem Wechsel von Login zu Menü / Seite1 weder ngOnInit noch ionViewWillEnter.
Wenn Sie zum Navigieren mit navCtrl.navigateRoot ('login') navigieren, wird nach dem Öffnen der Anmeldeseite die vorherige Seite gelöscht. Die Methoden ngOnInit und ionViewWillEnter funktionieren.

Das ist das Schöne an der Verwendung von navController - das
erwartete Verhalten stimmt voll und ganz mit dem aktuellen überein .