mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(vue): pages now render in correct outlet when using multiple nested outlets (#22301)
resolves #22286
This commit is contained in:
@ -6,14 +6,6 @@ import { RouteInfo,
|
|||||||
|
|
||||||
export const createViewStacks = () => {
|
export const createViewStacks = () => {
|
||||||
let viewStacks: ViewStacks = {};
|
let viewStacks: ViewStacks = {};
|
||||||
const tabsPrefixes = new Set();
|
|
||||||
|
|
||||||
const addTabsPrefix = (prefix: string) => tabsPrefixes.add(prefix);
|
|
||||||
const hasTabsPrefix = (path: string) => {
|
|
||||||
const values = Array.from(tabsPrefixes.values());
|
|
||||||
const hasPrefix = values.find((v: string) => path.includes(v));
|
|
||||||
return hasPrefix !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getViewStack = (outletId: number) => {
|
const getViewStack = (outletId: number) => {
|
||||||
return viewStacks[outletId];
|
return viewStacks[outletId];
|
||||||
@ -31,6 +23,19 @@ export const createViewStacks = () => {
|
|||||||
return findViewItemByPath(routeInfo.lastPathname, outletId);
|
return findViewItemByPath(routeInfo.lastPathname, outletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findViewItemByMatchedRoute = (matchedRoute: any, outletId: number): ViewItem | undefined => {
|
||||||
|
const stack = viewStacks[outletId];
|
||||||
|
if (!stack) return undefined;
|
||||||
|
|
||||||
|
return stack.find((viewItem: ViewItem) => {
|
||||||
|
if (viewItem.matchedRoute.path === matchedRoute.path) {
|
||||||
|
return viewItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const findViewItemInStack = (path: string, stack: ViewItem[]): ViewItem | undefined => {
|
const findViewItemInStack = (path: string, stack: ViewItem[]): ViewItem | undefined => {
|
||||||
return stack.find((viewItem: ViewItem) => {
|
return stack.find((viewItem: ViewItem) => {
|
||||||
if (viewItem.pathname === path) {
|
if (viewItem.pathname === path) {
|
||||||
@ -100,9 +105,8 @@ export const createViewStacks = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addTabsPrefix,
|
|
||||||
hasTabsPrefix,
|
|
||||||
findViewItemByRouteInfo,
|
findViewItemByRouteInfo,
|
||||||
|
findViewItemByMatchedRoute,
|
||||||
findLeavingViewItemByRouteInfo,
|
findLeavingViewItemByRouteInfo,
|
||||||
createViewItem,
|
createViewItem,
|
||||||
getChildrenToRender,
|
getChildrenToRender,
|
||||||
|
@ -19,17 +19,9 @@ export const IonRouterOutlet = defineComponent({
|
|||||||
setup(_, { attrs }) {
|
setup(_, { attrs }) {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const depth = inject(viewDepthKey, 0);
|
const depth = inject(viewDepthKey, 0);
|
||||||
|
|
||||||
// TODO types
|
|
||||||
let tabsPrefix: string | undefined;
|
|
||||||
const matchedRouteRef: any = computed(() => {
|
const matchedRouteRef: any = computed(() => {
|
||||||
const matchedRoute = route.matched[depth];
|
const matchedRoute = route.matched[depth];
|
||||||
|
|
||||||
if (attrs.tabs && !tabsPrefix) {
|
|
||||||
tabsPrefix = route.matched[0].path;
|
|
||||||
viewStacks.addTabsPrefix(tabsPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchedRoute && attrs.tabs && route.matched[depth + 1]) {
|
if (matchedRoute && attrs.tabs && route.matched[depth + 1]) {
|
||||||
return route.matched[route.matched.length - 1];
|
return route.matched[route.matched.length - 1];
|
||||||
}
|
}
|
||||||
@ -50,9 +42,10 @@ export const IonRouterOutlet = defineComponent({
|
|||||||
|
|
||||||
let skipTransition = false;
|
let skipTransition = false;
|
||||||
|
|
||||||
watch(matchedRouteRef, () => {
|
// The base url for this router outlet
|
||||||
setupViewItem(matchedRouteRef);
|
let parentOutletPath: string;
|
||||||
});
|
|
||||||
|
watch(matchedRouteRef, () => setupViewItem(matchedRouteRef));
|
||||||
|
|
||||||
const canStart = () => {
|
const canStart = () => {
|
||||||
const stack = viewStacks.getViewStack(id);
|
const stack = viewStacks.getViewStack(id);
|
||||||
@ -252,20 +245,46 @@ export const IonRouterOutlet = defineComponent({
|
|||||||
components.value = viewStacks.getChildrenToRender(id);
|
components.value = viewStacks.getChildrenToRender(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO types
|
|
||||||
const setupViewItem = (matchedRouteRef: any) => {
|
const setupViewItem = (matchedRouteRef: any) => {
|
||||||
if (!matchedRouteRef.value) {
|
const firstMatchedRoute = route.matched[0];
|
||||||
|
if (!parentOutletPath) {
|
||||||
|
parentOutletPath = firstMatchedRoute.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If no matched route, do not do anything in this outlet.
|
||||||
|
* If there is a match, but it the first matched path
|
||||||
|
* is not the root path for this outlet, then this view
|
||||||
|
* change needs to be rendered in a different outlet.
|
||||||
|
* We also add an exception for when the matchedRouteRef is
|
||||||
|
* equal to the first matched route (i.e. the base router outlet).
|
||||||
|
* This logic is mainly to help nested outlets/multi-tab
|
||||||
|
* setups work better.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
!matchedRouteRef.value ||
|
||||||
|
(matchedRouteRef.value !== firstMatchedRoute && firstMatchedRoute.path !== parentOutletPath)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentRoute = ionRouter.getCurrentRouteInfo();
|
const currentRoute = ionRouter.getCurrentRouteInfo();
|
||||||
const hasTabsPrefix = viewStacks.hasTabsPrefix(currentRoute.pathname)
|
|
||||||
const isLastPathTabs = viewStacks.hasTabsPrefix(currentRoute.lastPathname);
|
|
||||||
if (hasTabsPrefix && isLastPathTabs && !attrs.tabs) { return; }
|
|
||||||
|
|
||||||
let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id);
|
let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id);
|
||||||
|
|
||||||
if (!enteringViewItem) {
|
if (!enteringViewItem) {
|
||||||
|
/**
|
||||||
|
* If we have no existing entering item, we need
|
||||||
|
* make sure that there is no existing view according to the
|
||||||
|
* matched route rather than what is in the url bar.
|
||||||
|
* This is mainly for tabs when outlet 1 renders ion-tabs
|
||||||
|
* and outlet 2 renders the individual tab view. We don't
|
||||||
|
* want outlet 1 creating a new ion-tabs instance every time
|
||||||
|
* we switch tabs.
|
||||||
|
*/
|
||||||
|
if (viewStacks.findViewItemByMatchedRoute(matchedRouteRef.value, id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
|
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
|
||||||
viewStacks.add(enteringViewItem);
|
viewStacks.add(enteringViewItem);
|
||||||
}
|
}
|
||||||
|
32
packages/vue/test-app/package-lock.json
generated
32
packages/vue/test-app/package-lock.json
generated
@ -1306,27 +1306,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ionic/core": {
|
"@ionic/core": {
|
||||||
"version": "5.4.0-dev.202010081857.bfc0b25",
|
"version": "5.4.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.4.0-dev.202010081857.bfc0b25.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.4.0-rc.1.tgz",
|
||||||
"integrity": "sha512-yCH1GTlTTTS3dt9kYk/y5K82UdKOLidRqziGTsFeOoqTJI2w87SgRx0V0Il92dcB1XaWPB/SNnaM7Tt+GD7+Lg==",
|
"integrity": "sha512-8/Mcz86GZEA8Q9x86MOpWU+v4PQBmMfjja1LNVlGN+OIh2oIVBbY6EL6+dw9o6lcHoMY4bUHHpgyPvpYDNXfJw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ionicons": "^5.1.2",
|
"ionicons": "^5.1.2",
|
||||||
"tslib": "^1.10.0"
|
"tslib": "^1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ionic/vue": {
|
"@ionic/vue": {
|
||||||
"version": "5.4.0-dev.202010081857.bfc0b25",
|
"version": "5.4.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-5.4.0-dev.202010081857.bfc0b25.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-5.4.0-rc.1.tgz",
|
||||||
"integrity": "sha512-A2s0skOjoytlwC2xJVo+jmv6ZcYKV+HAaGitqKs08bPHATFDh+yzpJLXRkS0poZ3N2Bk4ossXsd5gn4eXC7cKw==",
|
"integrity": "sha512-DqlZIE61Awm3D1jNX6ADbGcfQWKhRZty1EZVjnJ9xPnPLm4h/yKUU2jRUwfN5ia7pYIvKoz+FAqwBgGxO4G8UQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ionic/core": "5.4.0-dev.202010081857.bfc0b25",
|
"@ionic/core": "5.4.0-rc.1",
|
||||||
"ionicons": "^5.1.2"
|
"ionicons": "^5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ionic/vue-router": {
|
"@ionic/vue-router": {
|
||||||
"version": "5.4.0-dev.202010081857.bfc0b25",
|
"version": "5.4.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-5.4.0-dev.202010081857.bfc0b25.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-5.4.0-rc.1.tgz",
|
||||||
"integrity": "sha512-qlFRY32CuttCZHqFFTZoDOERFFLDursJvMeb75KjE5lO/gD+dbelb7Cn0dOyaKyrM06X/lwb8eXgjCwSsGbHxg=="
|
"integrity": "sha512-Yq+yPJdaCdHZTEefes7ry9fEUyMkxPvxPjzc/e4vgDz1a3/UISM3SGfxP4qRv2RtRs5nbPv0tb1DZuPbMOYT9g=="
|
||||||
},
|
},
|
||||||
"@jest/console": {
|
"@jest/console": {
|
||||||
"version": "24.9.0",
|
"version": "24.9.0",
|
||||||
@ -7691,6 +7691,12 @@
|
|||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.7.0",
|
"version": "6.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||||
@ -12295,12 +12301,6 @@
|
|||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-to-regexp": {
|
|
||||||
"version": "0.1.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
|
||||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"path-type": {
|
"path-type": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
"sync": "sh ./scripts/sync.sh"
|
"sync": "sh ./scripts/sync.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ionic/vue": "5.4.0-dev.202010081857.bfc0b25",
|
"@ionic/vue": "^5.4.0-rc.1",
|
||||||
"@ionic/vue-router": "5.4.0-dev.202010081857.bfc0b25",
|
"@ionic/vue-router": "^5.4.0-rc.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"vue": "^3.0.0-0",
|
"vue": "^3.0.0-0",
|
||||||
"vue-router": "^4.0.0-0"
|
"vue-router": "^4.0.0-0"
|
||||||
|
@ -4,6 +4,11 @@ cp -a ../dist node_modules/@ionic/vue/dist
|
|||||||
cp -a ../css node_modules/@ionic/vue/css
|
cp -a ../css node_modules/@ionic/vue/css
|
||||||
cp -a ../package.json node_modules/@ionic/vue/package.json
|
cp -a ../package.json node_modules/@ionic/vue/package.json
|
||||||
|
|
||||||
|
# Copy ionic vue router dist
|
||||||
|
rm -rf node_modules/@ionic/vue-router/dist
|
||||||
|
cp -a ../../vue-router/dist node_modules/@ionic/vue-router/dist
|
||||||
|
cp -a ../../vue-router/package.json node_modules/@ionic/vue-router/package.json
|
||||||
|
|
||||||
# Copy core dist
|
# Copy core dist
|
||||||
rm -rf node_modules/@ionic/core/dist node_modules/@ionic/core/loader
|
rm -rf node_modules/@ionic/core/dist node_modules/@ionic/core/loader
|
||||||
cp -a ../../../core/dist node_modules/@ionic/core/dist
|
cp -a ../../../core/dist node_modules/@ionic/core/dist
|
||||||
|
@ -85,6 +85,28 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/tabs-secondary/',
|
||||||
|
component: () => import('@/views/TabsSecondary.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirect: '/tabs-secondary/tab1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tab1',
|
||||||
|
component: () => import('@/views/Tab1Secondary.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tab2',
|
||||||
|
component: () => import('@/views/Tab2Secondary.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tab3',
|
||||||
|
component: () => import('@/views/Tab3Secondary.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
<ion-item router-link="/tabs" id="tabs">
|
<ion-item router-link="/tabs" id="tabs">
|
||||||
<ion-label>Tabs</ion-label>
|
<ion-label>Tabs</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item router-link="/tabs-secondary" id="tab-secondary">
|
||||||
|
<ion-label>Tabs Secondary</ion-label>
|
||||||
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<div class="ion-padding">
|
<div class="ion-padding">
|
||||||
|
<ion-button router-link="/tabs/tab1" id="nested-tabs">Tab 1</ion-button>
|
||||||
<ion-button router-link="/nested/two" id="nested-child-two">Nested Child Two</ion-button>
|
<ion-button router-link="/nested/two" id="nested-child-two">Nested Child Two</ion-button>
|
||||||
</div>
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ion-page>
|
<ion-page data-pageid="routeroutlet">
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-router-outlet></ion-router-outlet>
|
<ion-router-outlet></ion-router-outlet>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
@ -20,6 +20,17 @@
|
|||||||
<ion-item router-link="tab1/child-one" id="child-one">
|
<ion-item router-link="tab1/child-one" id="child-one">
|
||||||
<ion-label>Go to Tab 1 Child 1</ion-label>
|
<ion-label>Go to Tab 1 Child 1</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item 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-label>Go to Secondary Tabs</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item router-link="/tabs" id="tabs-primary">
|
||||||
|
<ion-label>Go to Primary Tabs</ion-label>
|
||||||
|
</ion-item>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-page>
|
</ion-page>
|
||||||
</template>
|
</template>
|
||||||
|
34
packages/vue/test-app/src/views/Tab1Secondary.vue
Normal file
34
packages/vue/test-app/src/views/Tab1Secondary.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page data-pageid="tab1-secondary">
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons>
|
||||||
|
<ion-back-button default-href="/"></ion-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>Tab 1 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content :fullscreen="true">
|
||||||
|
<ion-header collapse="condense">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title size="large">Tab 1 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ExploreContainer name="Tab 1 page" />
|
||||||
|
|
||||||
|
<ion-item router-link="/tabs" id="tabs-primary">
|
||||||
|
<ion-label>Go to Primary Tabs</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { IonButtons, IonBackButton, IonPage, IonHeader, IonItem, IonLabel, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
|
||||||
|
import ExploreContainer from '@/components/ExploreContainer.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { IonButtons, IonBackButton, ExploreContainer, IonHeader, IonItem, IonLabel, IonToolbar, IonTitle, IonContent, IonPage }
|
||||||
|
}
|
||||||
|
</script>
|
27
packages/vue/test-app/src/views/Tab2Secondary.vue
Normal file
27
packages/vue/test-app/src/views/Tab2Secondary.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page data-pageid="tab2-secondary">
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title>Tab 2 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content :fullscreen="true">
|
||||||
|
<ion-header collapse="condense">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title size="large">Tab 2 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ExploreContainer name="Tab 2 page" />
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
|
||||||
|
import ExploreContainer from '@/components/ExploreContainer.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { ExploreContainer, IonHeader, IonToolbar, IonTitle, IonContent, IonPage }
|
||||||
|
}
|
||||||
|
</script>
|
27
packages/vue/test-app/src/views/Tab3Secondary.vue
Normal file
27
packages/vue/test-app/src/views/Tab3Secondary.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title>Tab 3 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content :fullscreen="true">
|
||||||
|
<ion-header collapse="condense">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title size="large">Tab 3 - Secondary</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ExploreContainer name="Tab 3 page" />
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
|
||||||
|
import ExploreContainer from '@/components/ExploreContainer.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { ExploreContainer, IonHeader, IonToolbar, IonTitle, IonContent, IonPage }
|
||||||
|
}
|
||||||
|
</script>
|
41
packages/vue/test-app/src/views/TabsSecondary.vue
Normal file
41
packages/vue/test-app/src/views/TabsSecondary.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page data-pageid="tabs-secondary">
|
||||||
|
<ion-content>
|
||||||
|
<ion-tabs id="tabs">
|
||||||
|
<ion-tab-bar slot="bottom">
|
||||||
|
<ion-tab-button tab="tab1" href="/tabs-secondary/tab1">
|
||||||
|
<ion-icon :icon="triangle" />
|
||||||
|
<ion-label>Tab 1</ion-label>
|
||||||
|
</ion-tab-button>
|
||||||
|
|
||||||
|
<ion-tab-button tab="tab2" href="/tabs-secondary/tab2">
|
||||||
|
<ion-icon :icon="ellipse" />
|
||||||
|
<ion-label>Tab 2</ion-label>
|
||||||
|
</ion-tab-button>
|
||||||
|
|
||||||
|
<ion-tab-button tab="tab3" href="/tabs-secondary/tab3">
|
||||||
|
<ion-icon :icon="square" />
|
||||||
|
<ion-label>Tab 3</ion-label>
|
||||||
|
</ion-tab-button>
|
||||||
|
</ion-tab-bar>
|
||||||
|
</ion-tabs>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { IonTabBar, IonTabButton, IonTabs, IonContent, IonLabel, IonIcon, IonPage } from '@ionic/vue';
|
||||||
|
import { ellipse, square, triangle } from 'ionicons/icons';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Tabs',
|
||||||
|
components: { IonContent, IonLabel, IonTabs, IonTabBar, IonTabButton, IonIcon, IonPage },
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
ellipse,
|
||||||
|
square,
|
||||||
|
triangle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -7,15 +7,29 @@ describe('Nested', () => {
|
|||||||
cy.ionPageVisible('nestedchild');
|
cy.ionPageVisible('nestedchild');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should go to second page', () => {
|
it('should go to second page', () => {
|
||||||
cy.get('#nested-child-two').click();
|
cy.get('#nested-child-two').click();
|
||||||
cy.ionPageVisible('nestedchildtwo');
|
cy.ionPageVisible('nestedchildtwo');
|
||||||
cy.ionPageInvisible('nestedchild');
|
cy.ionPageHidden('nestedchild');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should go back to first page', () => {
|
it('should go back to first page', () => {
|
||||||
cy.get('#nested-child-two').click();
|
cy.get('#nested-child-two').click();
|
||||||
cy.ionBackClick('nestedchildtwo');
|
cy.ionBackClick('nestedchildtwo');
|
||||||
cy.ionPageVisible('nestedchild');
|
cy.ionPageVisible('nestedchild');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should go navigate across nested outlet contexts', () => {
|
||||||
|
cy.ionPageVisible('nestedchild');
|
||||||
|
|
||||||
|
cy.get('#nested-tabs').click();
|
||||||
|
|
||||||
|
cy.ionPageHidden('routeroutlet');
|
||||||
|
cy.ionPageVisible('tab1');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1');
|
||||||
|
|
||||||
|
cy.ionPageDoesNotExist('tab1');
|
||||||
|
cy.ionPageVisible('routeroutlet');
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
@ -36,6 +36,21 @@ describe('Tabs', () => {
|
|||||||
cy.get('ion-tab-button#tab-button-tab1').click();
|
cy.get('ion-tab-button#tab-button-tab1').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should go to correct tab when going back via browser', () => {
|
||||||
|
cy.visit('http://localhost:8080/tabs')
|
||||||
|
|
||||||
|
cy.get('#child-one').click();
|
||||||
|
|
||||||
|
cy.get('ion-tab-button#tab-button-tab2').click();
|
||||||
|
cy.ionPageVisible('tab2');
|
||||||
|
cy.ionPageHidden('tab1childone');
|
||||||
|
|
||||||
|
cy.go('back');
|
||||||
|
|
||||||
|
cy.ionPageVisible('tab1childone');
|
||||||
|
cy.ionPageHidden('tab1');
|
||||||
|
});
|
||||||
|
|
||||||
// TODO this does not work
|
// TODO this does not work
|
||||||
it.skip('should return to tab root when clicking tab button', () => {
|
it.skip('should return to tab root when clicking tab button', () => {
|
||||||
cy.visit('http://localhost:8080/tabs')
|
cy.visit('http://localhost:8080/tabs')
|
||||||
@ -134,3 +149,30 @@ describe('Tabs - Swipe to Go Back', () => {
|
|||||||
cy.ionPageVisible('home');
|
cy.ionPageVisible('home');
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Multi Tabs', () => {
|
||||||
|
it('should navigate to multiple tabs instances', () => {
|
||||||
|
cy.visit('http://localhost:8080/tabs')
|
||||||
|
|
||||||
|
cy.get('#tabs-secondary').click();
|
||||||
|
cy.ionPageHidden('tabs');
|
||||||
|
cy.ionPageVisible('tabs-secondary');
|
||||||
|
|
||||||
|
cy.get('[data-pageid="tab1-secondary"] #tabs-primary').click();
|
||||||
|
cy.ionPageHidden('tabs-secondary');
|
||||||
|
cy.ionPageVisible('tabs');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1');
|
||||||
|
cy.ionPageVisible('tabs-secondary');
|
||||||
|
cy.ionPageDoesNotExist('tabs');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1-secondary');
|
||||||
|
cy.ionPageVisible('tabs');
|
||||||
|
cy.ionPageDoesNotExist('tabs-secondary');
|
||||||
|
|
||||||
|
cy.ionBackClick('tab1');
|
||||||
|
|
||||||
|
cy.ionPageVisible('home');
|
||||||
|
cy.ionPageDoesNotExist('tabs');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
Reference in New Issue
Block a user