mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 18:17:31 +08:00
fix(angular): adds tabs stack
This commit is contained in:

committed by
Manu MA

parent
d9172b7d68
commit
adae8d4ad1
@ -184,6 +184,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
|||||||
pop(deep = 1) {
|
pop(deep = 1) {
|
||||||
return this.stackCtrl.pop(deep);
|
return this.stackCtrl.pop(deep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLastUrl() {
|
||||||
|
const active = this.stackCtrl.getActive();
|
||||||
|
return active ? active.fullpath : undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitEvent(el: HTMLElement) {
|
function emitEvent(el: HTMLElement) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ComponentFactoryResolver, Directive, ElementRef, HostListener, Injector, ViewContainerRef } from '@angular/core';
|
import { ComponentFactoryResolver, ContentChild, Directive, ElementRef, HostListener, Injector, ViewContainerRef } from '@angular/core';
|
||||||
import { AngularDelegate } from '../../providers/angular-delegate';
|
import { AngularDelegate } from '../../providers/angular-delegate';
|
||||||
|
import { IonRouterOutlet } from './ion-router-outlet';
|
||||||
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
@ -7,19 +8,32 @@ import { AngularDelegate } from '../../providers/angular-delegate';
|
|||||||
})
|
})
|
||||||
export class TabDelegate {
|
export class TabDelegate {
|
||||||
|
|
||||||
|
@ContentChild(IonRouterOutlet) outlet?: IonRouterOutlet;
|
||||||
|
|
||||||
|
private nativeEl: HTMLIonTabElement;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private elementRef: ElementRef,
|
elementRef: ElementRef,
|
||||||
resolver: ComponentFactoryResolver,
|
resolver: ComponentFactoryResolver,
|
||||||
injector: Injector,
|
injector: Injector,
|
||||||
angularDelegate: AngularDelegate,
|
angularDelegate: AngularDelegate,
|
||||||
location: ViewContainerRef
|
location: ViewContainerRef
|
||||||
) {
|
) {
|
||||||
elementRef.nativeElement.delegate = angularDelegate.create(resolver, injector, location);
|
this.nativeEl = elementRef.nativeElement;
|
||||||
|
this.nativeEl.delegate = angularDelegate.create(resolver, injector, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
get tab() {
|
||||||
|
return this.nativeEl.tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastUrl() {
|
||||||
|
return this.outlet ? this.outlet.getLastUrl() : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('ionRouterOutletActivated', ['$event'])
|
@HostListener('ionRouterOutletActivated', ['$event'])
|
||||||
async onNavChanged() {
|
async onNavChanged() {
|
||||||
const tab = this.elementRef.nativeElement as HTMLIonTabElement;
|
const tab = this.nativeEl;
|
||||||
await tab.componentOnReady();
|
await tab.componentOnReady();
|
||||||
const tabs = tab.closest('ion-tabs');
|
const tabs = tab.closest('ion-tabs');
|
||||||
if (tabs) {
|
if (tabs) {
|
||||||
|
@ -1,25 +1,38 @@
|
|||||||
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
|
import { ContentChildren, Directive, ElementRef, HostListener, Optional, QueryList } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { TabDelegate } from './tab-delegate';
|
||||||
|
import { TabButtonClickDetail } from '@ionic/core';
|
||||||
|
import { NavController } from '../../providers';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'ion-tabs'
|
selector: 'ion-tabs'
|
||||||
})
|
})
|
||||||
export class TabsDelegate {
|
export class TabsDelegate {
|
||||||
|
|
||||||
|
@ContentChildren(TabDelegate) tabs: QueryList<TabDelegate>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Optional() private router: Router,
|
@Optional() private navCtrl: NavController,
|
||||||
elementRef: ElementRef
|
elementRef: ElementRef
|
||||||
) {
|
) {
|
||||||
if (router) {
|
const nativeEl = elementRef.nativeElement as HTMLIonTabsElement;
|
||||||
elementRef.nativeElement.useRouter = true;
|
nativeEl.useRouter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
urlForTab(tab: string) {
|
||||||
|
const tabDelegate = this.tabs.find(item => item.tab === tab);
|
||||||
|
return tabDelegate ? tabDelegate.getLastUrl() : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('ionTabButtonClick', ['$event'])
|
@HostListener('ionTabButtonClick', ['$event'])
|
||||||
onTabbarClick(ev: UIEvent) {
|
onTabbarClick(ev: any) {
|
||||||
const tabElm: HTMLIonTabButtonElement = ev.detail as any;
|
const detail = ev.detail as TabButtonClickDetail;
|
||||||
if (this.router && tabElm && tabElm.href) {
|
const { tab, href, selected } = detail;
|
||||||
this.router.navigateByUrl(tabElm.href);
|
if (tab && href) {
|
||||||
|
const url = selected
|
||||||
|
? href
|
||||||
|
: this.urlForTab(tab) || href;
|
||||||
|
|
||||||
|
this.navCtrl.navigateBack(url, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,7 +869,7 @@ export class TabButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export declare interface Tabs extends StencilComponents<'IonTabs'> {}
|
export declare interface Tabs extends StencilComponents<'IonTabs'> {}
|
||||||
@Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>' })
|
@Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['useRouter'] })
|
||||||
export class Tabs {
|
export class Tabs {
|
||||||
ionChange: EventEmitter<CustomEvent>;
|
ionChange: EventEmitter<CustomEvent>;
|
||||||
ionNavWillLoad: EventEmitter<CustomEvent>;
|
ionNavWillLoad: EventEmitter<CustomEvent>;
|
||||||
@ -880,6 +880,7 @@ export class Tabs {
|
|||||||
c.detach();
|
c.detach();
|
||||||
const el = r.nativeElement;
|
const el = r.nativeElement;
|
||||||
proxyMethods(this, el, ['select', 'setRouteId', 'getRouteId', 'getTab', 'getSelected']);
|
proxyMethods(this, el, ['select', 'setRouteId', 'getRouteId', 'getTab', 'getSelected']);
|
||||||
|
proxyInputs(this, el, ['useRouter']);
|
||||||
proxyOutputs(this, el, ['ionChange', 'ionNavWillLoad', 'ionNavWillChange', 'ionNavDidChange']);
|
proxyOutputs(this, el, ['ionChange', 'ionNavWillLoad', 'ionNavWillChange', 'ionNavDidChange']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
core/src/components.d.ts
vendored
2
core/src/components.d.ts
vendored
@ -4500,6 +4500,7 @@ export namespace Components {
|
|||||||
*/
|
*/
|
||||||
'select': (tab: string | HTMLIonTabElement) => Promise<boolean>;
|
'select': (tab: string | HTMLIonTabElement) => Promise<boolean>;
|
||||||
'setRouteId': (id: string) => Promise<RouteWrite>;
|
'setRouteId': (id: string) => Promise<RouteWrite>;
|
||||||
|
'useRouter': boolean;
|
||||||
}
|
}
|
||||||
interface IonTabsAttributes extends StencilHTMLAttributes {
|
interface IonTabsAttributes extends StencilHTMLAttributes {
|
||||||
/**
|
/**
|
||||||
@ -4518,6 +4519,7 @@ export namespace Components {
|
|||||||
* Emitted when the navigation will load a component.
|
* Emitted when the navigation will load a component.
|
||||||
*/
|
*/
|
||||||
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
|
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
|
||||||
|
'useRouter'?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IonText {
|
interface IonText {
|
||||||
|
@ -6,5 +6,6 @@ export interface TabBarChangedDetail {
|
|||||||
|
|
||||||
export interface TabButtonClickDetail {
|
export interface TabButtonClickDetail {
|
||||||
tab: string;
|
tab: string;
|
||||||
|
selected: boolean;
|
||||||
href?: string;
|
href?: string;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ export class TabButton implements ComponentInterface {
|
|||||||
if (!this.disabled) {
|
if (!this.disabled) {
|
||||||
this.ionTabButtonClick.emit({
|
this.ionTabButtonClick.emit({
|
||||||
tab: this.tab,
|
tab: this.tab,
|
||||||
href: this.href
|
href: this.href,
|
||||||
|
selected: this.selected
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
@ -87,6 +87,13 @@ Using tabs with Angular's router is fairly straight forward. The only additional
|
|||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Attribute | Description | Type | Default |
|
||||||
|
| ----------- | ------------ | ----------- | --------- | ------- |
|
||||||
|
| `useRouter` | `use-router` | | `boolean` | `false` |
|
||||||
|
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
| Event | Description | Detail |
|
| Event | Description | Detail |
|
||||||
|
@ -11,7 +11,6 @@ export class Tabs implements NavOutlet {
|
|||||||
|
|
||||||
private transitioning = false;
|
private transitioning = false;
|
||||||
private leavingTab?: HTMLIonTabElement;
|
private leavingTab?: HTMLIonTabElement;
|
||||||
private useRouter = false;
|
|
||||||
|
|
||||||
@Element() el!: HTMLStencilElement;
|
@Element() el!: HTMLStencilElement;
|
||||||
|
|
||||||
@ -21,6 +20,9 @@ export class Tabs implements NavOutlet {
|
|||||||
@Prop({ context: 'config' }) config!: Config;
|
@Prop({ context: 'config' }) config!: Config;
|
||||||
@Prop({ context: 'document' }) doc!: Document;
|
@Prop({ context: 'document' }) doc!: Document;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
@Prop({ mutable: true }) useRouter = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when the tab changes.
|
* Emitted when the tab changes.
|
||||||
*/
|
*/
|
||||||
@ -42,7 +44,9 @@ export class Tabs implements NavOutlet {
|
|||||||
@Event() ionNavDidChange!: EventEmitter<void>;
|
@Event() ionNavDidChange!: EventEmitter<void>;
|
||||||
|
|
||||||
async componentWillLoad() {
|
async componentWillLoad() {
|
||||||
|
if (!this.useRouter) {
|
||||||
this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]');
|
this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]');
|
||||||
|
}
|
||||||
this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
|
this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
|
||||||
this.ionNavWillLoad.emit();
|
this.ionNavWillLoad.emit();
|
||||||
this.componentWillUpdate();
|
this.componentWillUpdate();
|
||||||
@ -69,9 +73,9 @@ export class Tabs implements NavOutlet {
|
|||||||
protected onTabClicked(ev: CustomEvent<TabButtonClickDetail>) {
|
protected onTabClicked(ev: CustomEvent<TabButtonClickDetail>) {
|
||||||
const { href, tab } = ev.detail;
|
const { href, tab } = ev.detail;
|
||||||
const selectedTab = this.tabs.find(t => t.tab === tab);
|
const selectedTab = this.tabs.find(t => t.tab === tab);
|
||||||
if (this.useRouter && href !== undefined) {
|
if (this.useRouter) {
|
||||||
const router = this.doc.querySelector('ion-router');
|
const router = this.doc.querySelector('ion-router');
|
||||||
if (router) {
|
if (router && href !== undefined) {
|
||||||
router.push(href);
|
router.push(href);
|
||||||
}
|
}
|
||||||
} else if (selectedTab) {
|
} else if (selectedTab) {
|
||||||
|
Reference in New Issue
Block a user