refactor(vue): remove support for child routes nested inside of tabs (#22919)

BREAKING CHANGE: Support for child routes nested inside of tabs has been removed to better conform to Vue Router's best practices. Additional routes should be written as sibling routes with the parent tab as the path prefix.
This commit is contained in:
Liam DeBeasi
2021-02-12 14:43:29 -05:00
committed by GitHub
parent 9e05891736
commit 75458ac7fb
7 changed files with 105 additions and 96 deletions

View File

@ -17,26 +17,11 @@ import { fireLifecycle, generateId, getConfig } from '../utils';
let viewDepthKey: InjectionKey<0> = Symbol(0);
export const IonRouterOutlet = defineComponent({
name: 'IonRouterOutlet',
setup(_, { attrs }) {
setup() {
const injectedRoute = inject(routeLocationKey)!;
const route = useRoute();
const depth = inject(viewDepthKey, 0);
let usingDeprecatedRouteSetup = false;
// TODO: Remove in Ionic Vue v6.0
if (attrs.tabs && route.matched[depth]?.children?.length > 0) {
console.warn('[@ionic/vue Deprecation]: Your child routes are nested inside of each tab in your routing config. This format will not be supported in Ionic Vue v6.0. Instead, write your child routes as sibling routes. See https://ionicframework.com/docs/vue/navigation#child-routes-within-tabs for more information.');
usingDeprecatedRouteSetup = true;
}
const matchedRouteRef: any = computed(() => {
const matchedRoute = route.matched[depth];
if (matchedRoute && attrs.tabs && route.matched[depth + 1] && usingDeprecatedRouteSetup) {
return route.matched[route.matched.length - 1];
}
return matchedRoute;
});
const matchedRouteRef: any = computed(() => route.matched[depth]);
provide(viewDepthKey, depth + 1)
provide(matchedRouteKey, matchedRouteRef);
@ -83,15 +68,15 @@ 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, usingDeprecatedRouteSetup);
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, usingDeprecatedRouteSetup);
const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup);
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
if (leavingViewItem) {
let animationBuilder = routerAnimation;
@ -146,7 +131,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, usingDeprecatedRouteSetup);
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
enteringViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
enteringViewItem.ionPageElement.classList.add('ion-page-hidden');
}
@ -201,14 +186,14 @@ export const IonRouterOutlet = defineComponent({
const routeInfo = ionRouter.getCurrentRouteInfo();
const { routerDirection, routerAction, routerAnimation, prevRouteLastPathname } = routeInfo;
const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup);
let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id, true, usingDeprecatedRouteSetup);
const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id);
const enteringEl = enteringViewItem.ionPageElement;
if (enteringViewItem === leavingViewItem) return;
if (!leavingViewItem && prevRouteLastPathname) {
leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id, usingDeprecatedRouteSetup);
leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id);
}
fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER);
@ -303,7 +288,7 @@ export const IonRouterOutlet = defineComponent({
}
const currentRoute = ionRouter.getCurrentRouteInfo();
let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id, usingDeprecatedRouteSetup);
let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id);
if (!enteringViewItem) {
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);

View File

@ -19,7 +19,7 @@ export const IonTabs = defineComponent({
'contain': 'layout size style'
}
}, [
h(IonRouterOutlet, { tabs: true })
h(IonRouterOutlet)
])
];

View File

@ -83,41 +83,6 @@ const routes: Array<RouteRecordRaw> = [
path: '',
redirect: '/tabs/tab1'
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue'),
children: [
{
path: 'child-one',
component: () => import('@/views/Tab1ChildOne.vue')
},
{
path: 'child-two',
component: () => import('@/views/Tab1ChildTwo.vue')
}
]
},
{
path: 'tab2',
component: () => import('@/views/Tab2.vue')
},
{
path: 'tab3',
beforeEnter: (to, from, next) => {
next({ path: '/tabs/tab1' });
},
component: () => import('@/views/Tab3.vue')
}
]
},
{
path: '/tabs-new/',
component: () => import('@/views/Tabs.vue'),
children: [
{
path: '',
redirect: '/tabs-new/tab1'
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue'),

View File

@ -190,23 +190,6 @@ describe('Tabs', () => {
cy.ionPageVisible('tab2');
cy.ionPageVisible('tabs');
});
// Verifies 1 of 2 fixes for https://github.com/ionic-team/ionic-framework/issues/22519
it('should not create a new tabs instance when switching between tabbed and non-tabbed contexts - new tabs setup', () => {
cy.visit('http://localhost:8080/tabs-new/tab1');
cy.routerPush('/');
cy.ionPageHidden('tabs');
cy.ionPageVisible('home');
cy.routerPush('/tabs-new/tab2');
cy.ionPageHidden('tab1');
cy.ionPageHidden('home');
cy.ionPageVisible('tab2');
cy.ionPageVisible('tabs');
});
})
describe('Tabs - Swipe to Go Back', () => {

View File

@ -68,8 +68,7 @@ describe('ion-tab-bar', () => {
});
const innerHTML = wrapper.find('ion-tabs').html();
// TODO: Remove tabs="true" in Ionic Vue v6.0
expect(innerHTML).toContain(`<div class="tabs-inner" style="position: relative; flex: 1; contain: layout size style;"><ion-router-outlet tabs="true"></ion-router-outlet></div><ion-tab-bar slot="bottom"></ion-tab-bar>`);
expect(innerHTML).toContain(`<div class="tabs-inner" style="position: relative; flex: 1; contain: layout size style;"><ion-router-outlet></ion-router-outlet></div><ion-tab-bar slot="bottom"></ion-tab-bar>`);
});
@ -101,8 +100,7 @@ describe('ion-tab-bar', () => {
});
const innerHTML = wrapper.find('ion-tabs').html();
// TODO: Remove tabs="true" in Ionic Vue v6.0
expect(innerHTML).toContain(`<div class="tabs-inner" style="position: relative; flex: 1; contain: layout size style;"><ion-router-outlet tabs="true"></ion-router-outlet></div><ion-tab-bar></ion-tab-bar></ion-tabs>`)
expect(innerHTML).toContain(`<div class="tabs-inner" style="position: relative; flex: 1; contain: layout size style;"><ion-router-outlet></ion-router-outlet></div><ion-tab-bar></ion-tab-bar></ion-tabs>`)
});
// Verifies the fix for https://github.com/ionic-team/ionic-framework/issues/22642