mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 10:41:13 +08:00
@ -27,7 +27,8 @@ export const IonTabBar = defineComponent({
|
|||||||
* to a tab from another tab, we can correctly
|
* to a tab from another tab, we can correctly
|
||||||
* show any child pages if necessary.
|
* show any child pages if necessary.
|
||||||
*/
|
*/
|
||||||
(currentInstance.subTree.children as VNode[]).forEach((child: VNode) => {
|
const children = (currentInstance.subTree.children || []) as VNode[];
|
||||||
|
children.forEach((child: VNode) => {
|
||||||
if (child.type && (child.type as any).name === 'IonTabButton') {
|
if (child.type && (child.type as any).name === 'IonTabButton') {
|
||||||
tabState.tabs[child.props.tab] = {
|
tabState.tabs[child.props.tab] = {
|
||||||
originalHref: child.props.href,
|
originalHref: child.props.href,
|
||||||
@ -45,7 +46,7 @@ export const IonTabBar = defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const checkActiveTab = (currentRoute: any) => {
|
const checkActiveTab = (currentRoute: any) => {
|
||||||
const childNodes = currentInstance.subTree.children as VNode[];
|
const childNodes = (currentInstance.subTree.children || []) as VNode[];
|
||||||
const { tabs, activeTab: prevActiveTab } = tabState;
|
const { tabs, activeTab: prevActiveTab } = tabState;
|
||||||
const tabKeys = Object.keys(tabs);
|
const tabKeys = Object.keys(tabs);
|
||||||
const activeTab = tabKeys
|
const activeTab = tabKeys
|
||||||
|
@ -1,10 +1,50 @@
|
|||||||
import { h, defineComponent } from 'vue';
|
import { h, defineComponent, VNode } from 'vue';
|
||||||
import { IonRouterOutlet } from './IonRouterOutlet';
|
import { IonRouterOutlet } from './IonRouterOutlet';
|
||||||
|
|
||||||
export const IonTabs = defineComponent({
|
export const IonTabs = defineComponent({
|
||||||
name: 'IonTabs',
|
name: 'IonTabs',
|
||||||
render() {
|
render() {
|
||||||
const { $slots: slots } = this;
|
const { $slots: slots } = this;
|
||||||
|
const slottedContent = slots.default && slots.default();
|
||||||
|
let childrenToRender = [
|
||||||
|
h('div', {
|
||||||
|
class: 'tabs-inner',
|
||||||
|
style: {
|
||||||
|
'position': 'relative',
|
||||||
|
'flex': '1',
|
||||||
|
'contain': 'layout size style'
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
h(IonRouterOutlet, { tabs: true })
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If ion-tab-bar has slot="top" it needs to be
|
||||||
|
* rendered before `.tabs-inner` otherwise it will
|
||||||
|
* not show above the tab content.
|
||||||
|
*/
|
||||||
|
if (slottedContent && slottedContent.length > 0) {
|
||||||
|
const topSlottedTabBar = slottedContent.find((child: VNode) => {
|
||||||
|
const isTabBar = child.type && (child.type as any).name === 'IonTabBar';
|
||||||
|
const hasTopSlot = child.props?.slot === 'top';
|
||||||
|
|
||||||
|
return isTabBar && hasTopSlot;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (topSlottedTabBar) {
|
||||||
|
childrenToRender = [
|
||||||
|
...slottedContent,
|
||||||
|
...childrenToRender
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
childrenToRender = [
|
||||||
|
...childrenToRender,
|
||||||
|
...slottedContent
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return h(
|
return h(
|
||||||
'ion-tabs',
|
'ion-tabs',
|
||||||
{
|
{
|
||||||
@ -22,23 +62,7 @@ export const IonTabs = defineComponent({
|
|||||||
'z-index': '0'
|
'z-index': '0'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
childrenToRender
|
||||||
h(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
class: 'tabs-inner',
|
|
||||||
style: {
|
|
||||||
'position': 'relative',
|
|
||||||
'flex': '1',
|
|
||||||
'contain': 'layout size style'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h(IonRouterOutlet, { tabs: true })
|
|
||||||
]
|
|
||||||
),
|
|
||||||
...slots.default && slots.default()
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<ion-page data-pageid="tabs-secondary">
|
<ion-page data-pageid="tabs-secondary">
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-tabs id="tabs">
|
<ion-tabs id="tabs">
|
||||||
<ion-tab-bar slot="bottom">
|
<ion-tab-bar slot="top">
|
||||||
<ion-tab-button tab="tab1-secondary" href="/tabs-secondary/tab1">
|
<ion-tab-button tab="tab1-secondary" href="/tabs-secondary/tab1">
|
||||||
<ion-icon :icon="triangle" />
|
<ion-icon :icon="triangle" />
|
||||||
<ion-label>Tab 1</ion-label>
|
<ion-label>Tab 1</ion-label>
|
||||||
|
105
packages/vue/test-app/tests/unit/tab-bar.spec.ts
Normal file
105
packages/vue/test-app/tests/unit/tab-bar.spec.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { createRouter, createWebHistory } from '@ionic/vue-router';
|
||||||
|
import { IonicVue, IonApp, IonRouterOutlet, IonPage, IonTabs, IonTabBar } from '@ionic/vue';
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
components: { IonApp, IonRouterOutlet },
|
||||||
|
template: '<ion-app><ion-router-outlet /></ion-app>',
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ion-tab-bar', () => {
|
||||||
|
it('should render in the top slot', async () => {
|
||||||
|
const Tabs = {
|
||||||
|
components: { IonPage, IonTabs, IonTabBar },
|
||||||
|
template: `
|
||||||
|
<ion-page>
|
||||||
|
<ion-tabs>
|
||||||
|
<ion-tab-bar slot="top"></ion-tab-bar>
|
||||||
|
</ion-tabs>
|
||||||
|
</ion-page>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Tabs }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const innerHTML = wrapper.find('ion-tabs').html();
|
||||||
|
expect(innerHTML).toContain(`<ion-tab-bar slot="top"></ion-tab-bar><div class="tabs-inner" style="position: relative; flex: 1; contain: layout size style;">`);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render in the bottom slot', async () => {
|
||||||
|
const Tabs = {
|
||||||
|
components: { IonPage, IonTabs, IonTabBar },
|
||||||
|
template: `
|
||||||
|
<ion-page>
|
||||||
|
<ion-tabs>
|
||||||
|
<ion-tab-bar slot="bottom"></ion-tab-bar>
|
||||||
|
</ion-tabs>
|
||||||
|
</ion-page>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Tabs }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const innerHTML = wrapper.find('ion-tabs').html();
|
||||||
|
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>`);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render in the default slot', async () => {
|
||||||
|
const Tabs = {
|
||||||
|
components: { IonPage, IonTabs, IonTabBar },
|
||||||
|
template: `
|
||||||
|
<ion-page>
|
||||||
|
<ion-tabs>
|
||||||
|
<ion-tab-bar></ion-tab-bar>
|
||||||
|
</ion-tabs>
|
||||||
|
</ion-page>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: Tabs }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push('/');
|
||||||
|
await router.isReady();
|
||||||
|
const wrapper = mount(App, {
|
||||||
|
global: {
|
||||||
|
plugins: [router, IonicVue]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const innerHTML = wrapper.find('ion-tabs').html();
|
||||||
|
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>`)
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user