mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
fix(react, vue): correct view now chosen when going back inside tabs (#23154)
resolves #23087 resolves #23101
This commit is contained in:
@ -243,7 +243,19 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
|||||||
routeDirection: 'back',
|
routeDirection: 'back',
|
||||||
routeAnimation: routeAnimation || routeInfo.routeAnimation,
|
routeAnimation: routeAnimation || routeInfo.routeAnimation,
|
||||||
};
|
};
|
||||||
if (routeInfo.lastPathname === routeInfo.pushedByRoute || prevInfo.pathname === routeInfo.pushedByRoute) {
|
if (
|
||||||
|
routeInfo.lastPathname === routeInfo.pushedByRoute ||
|
||||||
|
(
|
||||||
|
/**
|
||||||
|
* We need to exclude tab switches/tab
|
||||||
|
* context changes here because tabbed
|
||||||
|
* navigation is not linear, but router.back()
|
||||||
|
* will go back in a linear fashion.
|
||||||
|
*/
|
||||||
|
prevInfo.pathname === routeInfo.pushedByRoute &&
|
||||||
|
routeInfo.tab === '' && prevInfo.tab === ''
|
||||||
|
)
|
||||||
|
) {
|
||||||
this.props.history.goBack();
|
this.props.history.goBack();
|
||||||
} else {
|
} else {
|
||||||
this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back');
|
this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back');
|
||||||
|
46
packages/react-router/test-app/cypress/integration/tabs.js
vendored
Normal file
46
packages/react-router/test-app/cypress/integration/tabs.js
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
describe('Tabs', () => {
|
||||||
|
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23101
|
||||||
|
it('should return to previous tab instance when using the ion-back-button', () => {
|
||||||
|
cy.visit(`http://localhost:${port}/tabs/tab1`);
|
||||||
|
|
||||||
|
cy.get('#tabs-secondary').click();
|
||||||
|
cy.ionPageVisible('tab1-secondary');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab2-secondary').click();
|
||||||
|
cy.ionPageHidden('tab1-secondary');
|
||||||
|
cy.ionPageVisible('tab2-secondary');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab1-secondary').click();
|
||||||
|
cy.ionPageHidden('tab2-secondary');
|
||||||
|
cy.ionPageVisible('tab1-secondary');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1-secondary');
|
||||||
|
cy.ionPageDoesNotExist('tabs-secondary');
|
||||||
|
cy.ionPageVisible('tab1');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23087
|
||||||
|
it('should return to correct view and url when going back from child page after switching tabs', () => {
|
||||||
|
cy.visit(`http://localhost:${port}/tabs/tab1`);
|
||||||
|
|
||||||
|
cy.get('#child-one').click();
|
||||||
|
cy.ionPageHidden('tab1');
|
||||||
|
cy.ionPageVisible('tab1child1');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab2').click();
|
||||||
|
cy.ionPageHidden('tab1child1');
|
||||||
|
cy.ionPageVisible('tab2');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab1').click();
|
||||||
|
cy.ionPageHidden('tab2');
|
||||||
|
cy.ionPageVisible('tab1child1');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1child1');
|
||||||
|
cy.ionPageDoesNotExist('tab1child1');
|
||||||
|
cy.ionPageVisible('tab1');
|
||||||
|
|
||||||
|
cy.url().should('include', '/tabs/tab1');
|
||||||
|
});
|
||||||
|
});
|
@ -34,6 +34,8 @@ import { OutletRef } from './pages/outlet-ref/OutletRef';
|
|||||||
import { SwipeToGoBack } from './pages/swipe-to-go-back/SwipToGoBack';
|
import { SwipeToGoBack } from './pages/swipe-to-go-back/SwipToGoBack';
|
||||||
import Refs from './pages/refs/Refs';
|
import Refs from './pages/refs/Refs';
|
||||||
import DynamicIonpageClassnames from './pages/dynamic-ionpage-classnames/DynamicIonpageClassnames';
|
import DynamicIonpageClassnames from './pages/dynamic-ionpage-classnames/DynamicIonpageClassnames';
|
||||||
|
import Tabs from './pages/tabs/Tabs';
|
||||||
|
import TabsSecondary from './pages/tabs/TabsSecondary';
|
||||||
debugger;
|
debugger;
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -51,6 +53,8 @@ const App: React.FC = () => {
|
|||||||
<Route path="/outlet-ref" component={OutletRef} />
|
<Route path="/outlet-ref" component={OutletRef} />
|
||||||
<Route path="/swipe-to-go-back" component={SwipeToGoBack} />
|
<Route path="/swipe-to-go-back" component={SwipeToGoBack} />
|
||||||
<Route path="/dynamic-ionpage-classnames" component={DynamicIonpageClassnames} />
|
<Route path="/dynamic-ionpage-classnames" component={DynamicIonpageClassnames} />
|
||||||
|
<Route path="/tabs" component={Tabs} />
|
||||||
|
<Route path="/tabs-secondary" component={TabsSecondary} />
|
||||||
<Route path="/refs" component={Refs} />
|
<Route path="/refs" component={Refs} />
|
||||||
</IonReactRouter>
|
</IonReactRouter>
|
||||||
</IonApp>
|
</IonApp>
|
||||||
|
95
packages/react-router/test-app/src/pages/tabs/Tabs.tsx
Normal file
95
packages/react-router/test-app/src/pages/tabs/Tabs.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonTabs,
|
||||||
|
IonRouterOutlet,
|
||||||
|
IonTabBar,
|
||||||
|
IonTabButton,
|
||||||
|
IonIcon,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonButtons,
|
||||||
|
IonBackButton,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonButton,
|
||||||
|
} from '@ionic/react';
|
||||||
|
import { Route, Redirect } from 'react-router';
|
||||||
|
import { triangle, square } from 'ionicons/icons';
|
||||||
|
|
||||||
|
interface Tabs {}
|
||||||
|
|
||||||
|
const Tabs: React.FC<Tabs> = () => {
|
||||||
|
return (
|
||||||
|
<IonTabs>
|
||||||
|
<IonRouterOutlet id="tabs">
|
||||||
|
<Route path="/tabs/tab1" component={Tab1} exact />
|
||||||
|
<Route path="/tabs/tab2" component={Tab2} exact />
|
||||||
|
<Route path="/tabs/tab1/child" component={Tab1Child1} exact />
|
||||||
|
<Redirect from="/tabs" to="/tabs/tab1" exact />
|
||||||
|
</IonRouterOutlet>
|
||||||
|
<IonTabBar slot="bottom">
|
||||||
|
<IonTabButton tab="tab1" href="/tabs/tab1">
|
||||||
|
<IonIcon icon={triangle} />
|
||||||
|
<IonLabel>Tab1</IonLabel>
|
||||||
|
</IonTabButton>
|
||||||
|
<IonTabButton tab="tab2" href="/tabs/tab2">
|
||||||
|
<IonIcon icon={square} />
|
||||||
|
<IonLabel>Tab2</IonLabel>
|
||||||
|
</IonTabButton>
|
||||||
|
</IonTabBar>
|
||||||
|
</IonTabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab1 = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="tab1">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Tab1</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<IonButton routerLink="/tabs/tab1/child" id="child-one">Go to Tab1Child1</IonButton>
|
||||||
|
<IonButton routerLink="/tabs-secondary/tab1" id="tabs-secondary">Go to Secondary Tabs</IonButton>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab1Child1 = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="tab1child1">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton />
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Tab1</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab2 = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="tab2">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Tab2</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
Tab 2
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tabs;
|
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonTabs,
|
||||||
|
IonRouterOutlet,
|
||||||
|
IonTabBar,
|
||||||
|
IonTabButton,
|
||||||
|
IonIcon,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonButtons,
|
||||||
|
IonBackButton,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonButton,
|
||||||
|
} from '@ionic/react';
|
||||||
|
import { Route, Redirect } from 'react-router';
|
||||||
|
import { triangle, square } from 'ionicons/icons';
|
||||||
|
|
||||||
|
interface TabsSecondary {}
|
||||||
|
|
||||||
|
const TabsSecondary: React.FC<TabsSecondary> = () => {
|
||||||
|
return (
|
||||||
|
<IonTabs>
|
||||||
|
<IonRouterOutlet id="tabs-secondary">
|
||||||
|
<Route path="/tabs-secondary/tab1" component={Tab1} exact />
|
||||||
|
<Route path="/tabs-secondary/tab2" component={Tab2} exact />
|
||||||
|
<Redirect from="/tabs-secondary" to="/tabs-secondary/tab1" exact />
|
||||||
|
</IonRouterOutlet>
|
||||||
|
<IonTabBar slot="bottom">
|
||||||
|
<IonTabButton tab="tab1-secondary" href="/tabs-secondary/tab1">
|
||||||
|
<IonIcon icon={triangle} />
|
||||||
|
<IonLabel>Tab1</IonLabel>
|
||||||
|
</IonTabButton>
|
||||||
|
<IonTabButton tab="tab2-secondary" href="/tabs-secondary/tab2">
|
||||||
|
<IonIcon icon={square} />
|
||||||
|
<IonLabel>Tab2</IonLabel>
|
||||||
|
</IonTabButton>
|
||||||
|
</IonTabBar>
|
||||||
|
</IonTabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab1 = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="tab1-secondary">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Tab1</IonTitle>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton />
|
||||||
|
</IonButtons>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
Tab 1
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab2 = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="tab2-secondary">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Tab2</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
Tab 2
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TabsSecondary;
|
@ -88,7 +88,19 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
|
|||||||
const prevInfo = locationHistory.findLastLocation(routeInfo);
|
const prevInfo = locationHistory.findLastLocation(routeInfo);
|
||||||
if (prevInfo) {
|
if (prevInfo) {
|
||||||
incomingRouteParams = { ...prevInfo, routerAction: 'pop', routerDirection: 'back', routerAnimation: routerAnimation || routeInfo.routerAnimation };
|
incomingRouteParams = { ...prevInfo, routerAction: 'pop', routerDirection: 'back', routerAnimation: routerAnimation || routeInfo.routerAnimation };
|
||||||
if (routeInfo.lastPathname === routeInfo.pushedByRoute || prevInfo.pathname === routeInfo.pushedByRoute) {
|
if (
|
||||||
|
routeInfo.lastPathname === routeInfo.pushedByRoute ||
|
||||||
|
(
|
||||||
|
/**
|
||||||
|
* We need to exclude tab switches/tab
|
||||||
|
* context changes here because tabbed
|
||||||
|
* navigation is not linear, but router.back()
|
||||||
|
* will go back in a linear fashion.
|
||||||
|
*/
|
||||||
|
prevInfo.pathname === routeInfo.pushedByRoute &&
|
||||||
|
routeInfo.tab === '' && prevInfo.tab === ''
|
||||||
|
)
|
||||||
|
) {
|
||||||
router.back();
|
router.back();
|
||||||
} else {
|
} else {
|
||||||
router.replace({ path: prevInfo.pathname, query: parseQuery(prevInfo.search) });
|
router.replace({ path: prevInfo.pathname, query: parseQuery(prevInfo.search) });
|
||||||
|
@ -220,6 +220,50 @@ describe('Tabs', () => {
|
|||||||
|
|
||||||
cy.get('ion-tab-button#tab-button-tab1').should('not.have.class', 'tab-selected');
|
cy.get('ion-tab-button#tab-button-tab1').should('not.have.class', 'tab-selected');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23101
|
||||||
|
it('should return to previous tab instance when using the ion-back-button', () => {
|
||||||
|
cy.visit('http://localhost:8080/tabs/tab1');
|
||||||
|
|
||||||
|
cy.get('#tabs-secondary').click();
|
||||||
|
cy.ionPageHidden('tabs');
|
||||||
|
cy.ionPageVisible('tab1-secondary');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab2-secondary').click();
|
||||||
|
cy.ionPageHidden('tab1-secondary');
|
||||||
|
cy.ionPageVisible('tab2-secondary');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab1-secondary').click();
|
||||||
|
cy.ionPageHidden('tab2-secondary');
|
||||||
|
cy.ionPageVisible('tab1-secondary');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1-secondary');
|
||||||
|
cy.ionPageDoesNotExist('tabs-secondary');
|
||||||
|
cy.ionPageVisible('tab1');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verifies fix for https://github.com/ionic-team/ionic-framework/issues/23087
|
||||||
|
it('should return to correct view and url when going back from child page after switching tabs', () => {
|
||||||
|
cy.visit('http://localhost:8080/tabs/tab1');
|
||||||
|
|
||||||
|
cy.get('#child-one').click();
|
||||||
|
cy.ionPageHidden('tab1');
|
||||||
|
cy.ionPageVisible('tab1childone');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab2').click();
|
||||||
|
cy.ionPageHidden('tab1childone');
|
||||||
|
cy.ionPageVisible('tab2');
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab1').click();
|
||||||
|
cy.ionPageHidden('tab2');
|
||||||
|
cy.ionPageVisible('tab1childone');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1childone');
|
||||||
|
cy.ionPageDoesNotExist('tab1childone');
|
||||||
|
cy.ionPageVisible('tab1');
|
||||||
|
|
||||||
|
cy.url().should('include', '/tabs/tab1');
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Tabs - Swipe to Go Back', () => {
|
describe('Tabs - Swipe to Go Back', () => {
|
||||||
|
Reference in New Issue
Block a user