mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 18:17:31 +08:00
fix(vue): correctly determine leaving view when transitioning to a new instance of a previous page (#22655)
resolves #22654 resolves #22658
This commit is contained in:
@ -76,14 +76,14 @@ export const IonRouterOutlet = defineComponent({
|
||||
* to make sure the view is in the outlet we want.
|
||||
*/
|
||||
const routeInfo = ionRouter.getCurrentRouteInfo();
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute }, id);
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
|
||||
|
||||
return !!enteringViewItem;
|
||||
}
|
||||
const onStart = async () => {
|
||||
const routeInfo = ionRouter.getCurrentRouteInfo();
|
||||
const { routerAnimation } = routeInfo;
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute }, id);
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
|
||||
const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
|
||||
|
||||
if (leavingViewItem) {
|
||||
@ -139,7 +139,7 @@ export const IonRouterOutlet = defineComponent({
|
||||
* re-hide the page that was going to enter.
|
||||
*/
|
||||
const routeInfo = ionRouter.getCurrentRouteInfo();
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute }, id);
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
|
||||
enteringViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
enteringViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
}
|
||||
@ -192,17 +192,21 @@ export const IonRouterOutlet = defineComponent({
|
||||
|
||||
const handlePageTransition = async () => {
|
||||
const routeInfo = ionRouter.getCurrentRouteInfo();
|
||||
const { routerDirection, routerAction, routerAnimation } = routeInfo;
|
||||
const { routerDirection, routerAction, routerAnimation, prevRouteLastPathname } = routeInfo;
|
||||
|
||||
const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
|
||||
const leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id);
|
||||
let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id);
|
||||
const enteringEl = enteringViewItem.ionPageElement;
|
||||
|
||||
if (enteringViewItem === leavingViewItem) return;
|
||||
|
||||
if (!leavingViewItem && prevRouteLastPathname) {
|
||||
leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER);
|
||||
|
||||
if (leavingViewItem) {
|
||||
if (leavingViewItem && enteringViewItem !== leavingViewItem) {
|
||||
let animationBuilder = routerAnimation;
|
||||
const leavingEl = leavingViewItem.ionPageElement;
|
||||
|
||||
|
@ -68,6 +68,10 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: 'two',
|
||||
component: () => import('@/views/NestedChildTwo.vue')
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: () => import('@/views/Folder.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -135,4 +139,6 @@ const router = createRouter({
|
||||
routes
|
||||
});
|
||||
|
||||
(window as any).debugRouter = router;
|
||||
|
||||
export default router
|
||||
|
82
packages/vue/test-app/src/views/Folder.vue
Normal file
82
packages/vue/test-app/src/views/Folder.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<ion-page data-pageid="folder">
|
||||
<ion-header :translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ folder }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">{{ folder }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<div id="container">
|
||||
<strong class="capitalize">{{ folder }}</strong>
|
||||
<p>Explore <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'Folder',
|
||||
components: {
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonMenuButton,
|
||||
IonPage,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
},
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const folder = ref(route.params.id || 'Inbox');
|
||||
const matchedFolder = computed(() => route.params.id);
|
||||
|
||||
watch(matchedFolder, () => {
|
||||
folder.value = matchedFolder.value as string;
|
||||
})
|
||||
|
||||
return { folder }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#container strong {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
#container p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#container a {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
@ -14,37 +14,37 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-list>
|
||||
<ion-item router-link="/overlays">
|
||||
<ion-item button router-link="/overlays">
|
||||
<ion-label>Overlays</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/inputs">
|
||||
<ion-item button router-link="/inputs">
|
||||
<ion-label>Inputs</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/slides">
|
||||
<ion-item button router-link="/slides">
|
||||
<ion-label>Slides</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/navigation" id="navigation">
|
||||
<ion-item button router-link="/navigation" id="navigation">
|
||||
<ion-label>Navigation</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/routing" id="routing">
|
||||
<ion-item button router-link="/routing" id="routing">
|
||||
<ion-label>Routing</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/default-href" id="default-href">
|
||||
<ion-item button router-link="/default-href" id="default-href">
|
||||
<ion-label>Default Href</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/nested" id="nested">
|
||||
<ion-item button router-link="/nested" id="nested">
|
||||
<ion-label>Nested Router Outlet</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/tabs" id="tabs">
|
||||
<ion-item button router-link="/tabs" id="tabs">
|
||||
<ion-label>Tabs</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/tabs-secondary" id="tab-secondary">
|
||||
<ion-item button router-link="/tabs-secondary" id="tab-secondary">
|
||||
<ion-label>Tabs Secondary</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/lifecycle" id="lifecycle">
|
||||
<ion-item button router-link="/lifecycle" id="lifecycle">
|
||||
<ion-label>Lifecycle</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/delayed-redirect" id="delayed-redirect">
|
||||
<ion-item button router-link="/delayed-redirect" id="delayed-redirect">
|
||||
<ion-label>Delayed Redirect</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
@ -1,5 +1,16 @@
|
||||
<template>
|
||||
<ion-page data-pageid="routeroutlet">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button id="inbox" router-link="/nested/inbox" router-direction="root">Inbox</ion-button>
|
||||
<ion-button id="trash" router-link="/nested/trash" router-direction="root">Trash</ion-button>
|
||||
<ion-button id="outbox" router-link="/nested/outbox" router-direction="root">Outbox</ion-button>
|
||||
<ion-button id="spam" router-link="/nested/spam" router-direction="root">Spam</ion-button>
|
||||
<ion-button id="other" router-link="/nested/two" router-direction="root">Other</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-router-outlet></ion-router-outlet>
|
||||
</ion-content>
|
||||
@ -8,6 +19,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
IonHeader,
|
||||
IonButtons,
|
||||
IonButton,
|
||||
IonToolbar,
|
||||
IonContent,
|
||||
IonPage,
|
||||
IonRouterOutlet,
|
||||
@ -17,6 +32,10 @@ import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'RouterOutlet',
|
||||
components: {
|
||||
IonHeader,
|
||||
IonButtons,
|
||||
IonButton,
|
||||
IonToolbar,
|
||||
IonContent,
|
||||
IonPage,
|
||||
IonRouterOutlet
|
||||
|
@ -39,6 +39,10 @@
|
||||
<ion-item button @click="replace" id="replace">
|
||||
<ion-label>Replace to Navigation page</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item button router-link="/tabs/tab1" id="tab1">
|
||||
<ion-label>Go to /tabs/tab1</ion-label>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
@ -17,18 +17,18 @@
|
||||
|
||||
<ExploreContainer name="Tab 1 page" />
|
||||
|
||||
<ion-item router-link="/tabs/tab1/child-one" id="child-one">
|
||||
<ion-item button router-link="/tabs/tab1/child-one" id="child-one">
|
||||
<ion-label>Go to Tab 1 Child 1</ion-label>
|
||||
</ion-item>
|
||||
<ion-item router-link="/nested" id="nested">
|
||||
<ion-item button router-link="/nested" id="nested">
|
||||
<ion-label>Go to Nested Outlet</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item router-link="/tabs-secondary" id="tabs-secondary">
|
||||
<ion-item button router-link="/tabs-secondary" id="tabs-secondary">
|
||||
<ion-label>Go to Secondary Tabs</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item router-link="/tabs" id="tabs-primary">
|
||||
<ion-item button router-link="/tabs" id="tabs-primary">
|
||||
<ion-label>Go to Primary Tabs</ion-label>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
|
@ -15,17 +15,37 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ExploreContainer name="Tab 2 page" />
|
||||
<ion-item button router-link="/routing" id="routing">
|
||||
<ion-label>Go to /routing</ion-label>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IonButtons, IonBackButton, IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
|
||||
import ExploreContainer from '@/components/ExploreContainer.vue';
|
||||
import {
|
||||
IonButtons,
|
||||
IonBackButton,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonPage,
|
||||
IonHeader,
|
||||
IonToolbar,
|
||||
IonTitle,
|
||||
IonContent
|
||||
} from '@ionic/vue';
|
||||
|
||||
export default {
|
||||
name: 'Tab2',
|
||||
components: { IonButtons, IonBackButton, ExploreContainer, IonHeader, IonToolbar, IonTitle, IonContent, IonPage }
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
IonButtons,
|
||||
IonBackButton,
|
||||
IonItem,
|
||||
IonLabel,
|
||||
IonPage,
|
||||
IonHeader,
|
||||
IonToolbar,
|
||||
IonTitle,
|
||||
IonContent
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -11,7 +11,7 @@
|
||||
<ion-title size="large">Tab 3</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
<ExploreContainer name="Tab 3 page" />
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
@ -25,4 +25,4 @@ export default {
|
||||
name: 'Tab3',
|
||||
components: { ExploreContainer, IonHeader, IonToolbar, IonTitle, IonContent, IonPage }
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
@ -119,6 +119,63 @@ describe('Routing', () => {
|
||||
cy.ionSwipeToGoBack(true);
|
||||
cy.ionPageVisible('navigation');
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22654
|
||||
it('should show correct view when navigating between parameter urls', () => {
|
||||
cy.visit('http://localhost:8080/nested');
|
||||
|
||||
cy.ionPageVisible('nestedchild');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #trash').click();
|
||||
cy.ionPageVisible('folder');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #outbox').click();
|
||||
cy.ionPageVisible('folder');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #other').click();
|
||||
cy.ionPageVisible('nestedchildtwo');
|
||||
cy.ionPageDoesNotExist('folder');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #spam').click();
|
||||
cy.ionPageVisible('folder');
|
||||
cy.ionPageDoesNotExist('nestedchildtwo');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #outbox').click();
|
||||
cy.ionPageVisible('folder');
|
||||
|
||||
cy.get('[data-pageid="routeroutlet"] #other').click();
|
||||
cy.ionPageVisible('nestedchildtwo');
|
||||
cy.ionPageDoesNotExist('folder');
|
||||
});
|
||||
|
||||
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/22658
|
||||
it('should select correct leaving view when navigating between paramter urls', () => {
|
||||
cy.visit('http://localhost:8080');
|
||||
|
||||
cy.routerPush('/routing/123');
|
||||
cy.ionPageVisible('routingparameter');
|
||||
cy.ionPageHidden('home');
|
||||
|
||||
cy.routerPush('/routing/456');
|
||||
cy.ionPageVisible('routingparameter');
|
||||
cy.ionPageHidden('home');
|
||||
|
||||
cy.routerPush('/navigation');
|
||||
cy.ionPageVisible('navigation');
|
||||
cy.ionPageHidden('routingparameter');
|
||||
|
||||
cy.routerPush('/routing/789');
|
||||
cy.ionPageVisible('routingparameter');
|
||||
cy.ionPageHidden('home');
|
||||
|
||||
cy.routerPush('/routing/000');
|
||||
cy.ionPageVisible('routingparameter');
|
||||
cy.ionPageHidden('home');
|
||||
|
||||
cy.routerPush('/navigation');
|
||||
cy.ionPageVisible('navigation');
|
||||
cy.ionPageHidden('routingparameter');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Routing - Swipe to Go Back', () => {
|
||||
|
@ -85,6 +85,8 @@ describe('Tabs', () => {
|
||||
});
|
||||
|
||||
it('should go back from a tabs page to a non-tabs page using ion-back-button', () => {
|
||||
cy.visit('http://localhost:8080');
|
||||
|
||||
cy.get('#tabs').click();
|
||||
cy.ionPageVisible('tab1');
|
||||
|
||||
@ -97,6 +99,8 @@ describe('Tabs', () => {
|
||||
});
|
||||
|
||||
it('should properly clear stack when leaving tabs', () => {
|
||||
cy.visit('http://localhost:8080/');
|
||||
|
||||
cy.get('#tabs').click();
|
||||
cy.ionPageVisible('tab1');
|
||||
|
||||
@ -147,6 +151,28 @@ describe('Tabs', () => {
|
||||
cy.ionPageVisible('tab3-secondary');
|
||||
cy.ionPageHidden('tab1-secondary');
|
||||
});
|
||||
|
||||
// Verifies 1 of 2 fixes for https://github.com/ionic-team/ionic-framework/issues/22519
|
||||
it('should show correct tab when switching between tabbed and non-tabbed contexts', () => {
|
||||
cy.visit('http://localhost:8080/routing');
|
||||
|
||||
cy.get('[data-pageid="routing"] #tab1').click();
|
||||
cy.ionPageHidden('routing');
|
||||
cy.ionPageVisible('tab1');
|
||||
|
||||
cy.get('ion-tab-button#tab-button-tab2').click();
|
||||
cy.ionPageHidden('tab1');
|
||||
cy.ionPageVisible('tab2');
|
||||
|
||||
cy.get('[data-pageid="tab2"] #routing').click();
|
||||
cy.ionPageVisible('routing');
|
||||
cy.ionPageHidden('tabs');
|
||||
|
||||
cy.get('[data-pageid="routing"] #tab1').click();
|
||||
cy.ionPageVisible('tab1');
|
||||
cy.ionPageHidden('routing');
|
||||
cy.ionPageHidden('tab2');
|
||||
})
|
||||
})
|
||||
|
||||
describe('Tabs - Swipe to Go Back', () => {
|
||||
|
@ -71,3 +71,9 @@ Cypress.Commands.add('ionPageDoesNotExist', (pageId) => {
|
||||
cy.get(`div.ion-page[data-pageid=${pageId}]`)
|
||||
.should('not.exist')
|
||||
});
|
||||
|
||||
Cypress.Commands.add('routerPush', (path) => {
|
||||
cy.window().then(win => {
|
||||
win.debugRouter.push(path);
|
||||
});
|
||||
})
|
||||
|
Reference in New Issue
Block a user