diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index e5053f7aa3a..ff9a05a8644 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -14,6 +14,10 @@ import { AnimationBuilder, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_W import { matchedRouteKey, routeLocationKey, useRoute } from 'vue-router'; import { fireLifecycle, generateId, getConfig } from '../utils'; +const isViewVisible = (enteringEl: HTMLElement) => { + return !enteringEl.classList.contains('ion-page-hidden') && !enteringEl.classList.contains('ion-page-invisible'); +} + let viewDepthKey: InjectionKey<0> = Symbol(0); export const IonRouterOutlet = defineComponent({ name: 'IonRouterOutlet', @@ -230,13 +234,35 @@ export const IonRouterOutlet = defineComponent({ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.`); } - if (enteringViewItem === leavingViewItem) return; if (!leavingViewItem && prevRouteLastPathname) { leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id, usingDeprecatedRouteSetup); } + /** + * If the entering view is already + * visible, then no transition is needed. + * This is most common when navigating + * from a tabs page to a non-tabs page + * and then back to the tabs page. + * Even when the tabs context navigated away, + * the inner tabs page was still active. + * This also avoids an issue where + * the previous tabs page is incorrectly + * unmounted since it would automatically + * unmount the previous view. + * + * This should also only apply to entering and + * leaving items in the same router outlet (i.e. + * Tab1 and Tab2), otherwise this will + * return early for swipe to go back when + * going from a non-tabs page to a tabs page. + */ + if (isViewVisible(enteringEl) && leavingViewItem !== undefined && !isViewVisible(leavingViewItem.ionPageElement)) { + return; + } + fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER); if (leavingViewItem && enteringViewItem !== leavingViewItem) { diff --git a/packages/vue/test-app/tests/e2e/specs/tabs.js b/packages/vue/test-app/tests/e2e/specs/tabs.js index 376ebfa1a33..2657b8d56a9 100644 --- a/packages/vue/test-app/tests/e2e/specs/tabs.js +++ b/packages/vue/test-app/tests/e2e/specs/tabs.js @@ -307,7 +307,7 @@ describe('Tabs', () => { cy.url().should('include', '/tabs/tab1/child-one?key=value'); }); - // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23699 + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/24353 it('should handle clicking tab multiple times without query string', () => { cy.visit('http://localhost:8080/tabs/tab1'); @@ -329,6 +329,33 @@ describe('Tabs', () => { cy.ionPageVisible('tab2'); cy.ionPageHidden('tab1'); }); + + // Verifies fix for https://github.com/ionic-team/ionic-framework/issues/24332 + it('should not unmount tab 1 when leaving tabs context', () => { + cy.visit('http://localhost:8080/tabs'); + cy.ionPageVisible('tab1'); + + // Dynamically add tab 4 because tab 3 redirects to tab 1 + cy.get('#add-tab').click(); + + cy.get('ion-tab-button#tab-button-tab4').click(); + cy.ionPageHidden('tab1'); + cy.ionPageVisible('tab4'); + + cy.get('ion-tab-button#tab-button-tab2').click(); + cy.ionPageHidden('tab4'); + cy.ionPageVisible('tab2'); + + cy.get('[data-pageid="tab2"] #routing').click(); + cy.ionPageVisible('routing'); + cy.ionPageHidden('tabs'); + + cy.ionBackClick('routing'); + cy.ionPageDoesNotExist('routing'); + cy.ionPageVisible('tabs'); + cy.ionPageVisible('tab2'); + cy.ionPageHidden('tab1'); + }); }) describe('Tabs - Swipe to Go Back', () => {