mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
feat(react, vue, angular): use tabs without router (#29794)
Issue number: resolves #25184 --------- Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com> Co-authored-by: Sean Perkins <13732623+sean-perkins@users.noreply.github.com>
This commit is contained in:
@ -7,6 +7,8 @@ import {
|
||||
HostListener,
|
||||
Output,
|
||||
ViewChild,
|
||||
AfterViewInit,
|
||||
QueryList,
|
||||
} from '@angular/core';
|
||||
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
@ -17,14 +19,15 @@ import { StackDidChangeEvent, StackWillChangeEvent } from './stack-utils';
|
||||
selector: 'ion-tabs',
|
||||
})
|
||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||
export abstract class IonTabs implements AfterContentInit, AfterContentChecked {
|
||||
export abstract class IonTabs implements AfterViewInit, AfterContentInit, AfterContentChecked {
|
||||
/**
|
||||
* Note: These must be redeclared on each child class since it needs
|
||||
* access to generated components such as IonRouterOutlet and IonTabBar.
|
||||
*/
|
||||
abstract outlet: any;
|
||||
abstract tabBar: any;
|
||||
abstract tabBars: any;
|
||||
abstract tabBars: QueryList<any>;
|
||||
abstract tabs: QueryList<any>;
|
||||
|
||||
@ViewChild('tabsInner', { read: ElementRef, static: true }) tabsInner: ElementRef<HTMLDivElement>;
|
||||
|
||||
@ -39,8 +42,29 @@ export abstract class IonTabs implements AfterContentInit, AfterContentChecked {
|
||||
|
||||
private tabBarSlot = 'bottom';
|
||||
|
||||
private hasTab = false;
|
||||
private selectedTab?: { tab: string };
|
||||
private leavingTab?: any;
|
||||
|
||||
constructor(private navCtrl: NavController) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
/**
|
||||
* Developers must pass at least one ion-tab
|
||||
* inside of ion-tabs if they want to use a
|
||||
* basic tab-based navigation without the
|
||||
* history stack or URL updates associated
|
||||
* with the router.
|
||||
*/
|
||||
const firstTab = this.tabs.length > 0 ? this.tabs.first : undefined;
|
||||
|
||||
if (firstTab) {
|
||||
this.hasTab = true;
|
||||
this.setActiveTab(firstTab.tab);
|
||||
this.tabSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this.detectSlotChanges();
|
||||
}
|
||||
@ -96,6 +120,19 @@ export abstract class IonTabs implements AfterContentInit, AfterContentChecked {
|
||||
select(tabOrEvent: string | CustomEvent): Promise<boolean> | undefined {
|
||||
const isTabString = typeof tabOrEvent === 'string';
|
||||
const tab = isTabString ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
|
||||
|
||||
/**
|
||||
* If the tabs are not using the router, then
|
||||
* the tab switch logic is handled by the tabs
|
||||
* component itself.
|
||||
*/
|
||||
if (this.hasTab) {
|
||||
this.setActiveTab(tab);
|
||||
this.tabSwitch();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const alreadySelected = this.outlet.getActiveStackId() === tab;
|
||||
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
|
||||
|
||||
@ -142,7 +179,46 @@ export abstract class IonTabs implements AfterContentInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
private setActiveTab(tab: string): void {
|
||||
const tabs = this.tabs;
|
||||
const selectedTab = tabs.find((t: any) => t.tab === tab);
|
||||
|
||||
if (!selectedTab) {
|
||||
console.error(`[Ionic Error]: Tab with id: "${tab}" does not exist`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.leavingTab = this.selectedTab;
|
||||
this.selectedTab = selectedTab;
|
||||
|
||||
this.ionTabsWillChange.emit({ tab });
|
||||
|
||||
selectedTab.el.active = true;
|
||||
}
|
||||
|
||||
private tabSwitch(): void {
|
||||
const { selectedTab, leavingTab } = this;
|
||||
|
||||
if (this.tabBar && selectedTab) {
|
||||
this.tabBar.selectedTab = selectedTab.tab;
|
||||
}
|
||||
|
||||
if (leavingTab?.tab !== selectedTab?.tab) {
|
||||
if (leavingTab?.el) {
|
||||
leavingTab.el.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTab) {
|
||||
this.ionTabsDidChange.emit({ tab: selectedTab.tab });
|
||||
}
|
||||
}
|
||||
|
||||
getSelected(): string | undefined {
|
||||
if (this.hasTab) {
|
||||
return this.selectedTab?.tab;
|
||||
}
|
||||
|
||||
return this.outlet.getActiveStackId();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user