mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 03:00:58 +08:00
feat(angular): add tabs events (#17125)
* feat(angular): add tabs events * lint
This commit is contained in:
@ -25,6 +25,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
|
||||
tabsPrefix: string | undefined;
|
||||
|
||||
@Output() stackEvents = new EventEmitter<any>();
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
@ -173,9 +174,9 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
this.activatedView = enteringView;
|
||||
this.stackCtrl.setActive(enteringView).then(() => {
|
||||
this.stackCtrl.setActive(enteringView).then(data => {
|
||||
this.activateEvents.emit(cmpRef.instance);
|
||||
emitEvent(this.nativeEl, enteringView!);
|
||||
this.stackEvents.emit(data);
|
||||
});
|
||||
}
|
||||
|
||||
@ -197,15 +198,6 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
function emitEvent(el: HTMLElement, view: RouteView) {
|
||||
const ev = new CustomEvent('ionRouterOutletActivated', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
detail: { view }
|
||||
});
|
||||
el.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
class OutletInjector implements Injector {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { Component, ContentChild, HostListener, ViewChild } from '@angular/core';
|
||||
import { Component, ContentChild, EventEmitter, HostListener, Output, ViewChild } from '@angular/core';
|
||||
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
import { IonTabBar } from '../proxies';
|
||||
|
||||
import { IonRouterOutlet } from './ion-router-outlet';
|
||||
import { RouteView } from './stack-utils';
|
||||
import { StackEvent } from './stack-utils';
|
||||
|
||||
@Component({
|
||||
selector: 'ion-tabs',
|
||||
template: `
|
||||
<ng-content select="[slot=top]"></ng-content>
|
||||
<div class="tabs-inner">
|
||||
<ion-router-outlet #outlet tabs="true"></ion-router-outlet>
|
||||
<ion-router-outlet #outlet tabs="true" (stackEvents)="onPageSelected($event)"></ion-router-outlet>
|
||||
</div>
|
||||
<ng-content></ng-content>`,
|
||||
styles: [`
|
||||
@ -45,6 +45,9 @@ export class IonTabs {
|
||||
@ViewChild('outlet', { read: IonRouterOutlet }) outlet: IonRouterOutlet;
|
||||
@ContentChild(IonTabBar) tabBar: IonTabBar | undefined;
|
||||
|
||||
@Output() ionTabsWillChange = new EventEmitter<{tab: string}>();
|
||||
@Output() ionTabsDidChange = new EventEmitter<{tab: string}>();
|
||||
|
||||
constructor(
|
||||
private navCtrl: NavController,
|
||||
) {}
|
||||
@ -52,10 +55,14 @@ export class IonTabs {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@HostListener('ionRouterOutletActivated', ['$event.detail'])
|
||||
onPageSelected(detail: {view: RouteView}) {
|
||||
if (this.tabBar) {
|
||||
this.tabBar.selectedTab = detail.view.stackId;
|
||||
onPageSelected(detail: StackEvent) {
|
||||
const stackId = detail.enteringView.stackId;
|
||||
if (detail.tabSwitch && stackId !== undefined) {
|
||||
if (this.tabBar) {
|
||||
this.tabBar.selectedTab = stackId;
|
||||
}
|
||||
this.ionTabsWillChange.emit({ tab: stackId });
|
||||
this.ionTabsDidChange.emit({ tab: stackId });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { RouterDirection } from '@ionic/core';
|
||||
import { bindLifecycleEvents } from '../../providers/angular-delegate';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
import { RouteView, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
|
||||
import { RouteView, StackEvent, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
|
||||
|
||||
export class StackController {
|
||||
|
||||
@ -50,16 +50,23 @@ export class StackController {
|
||||
return view;
|
||||
}
|
||||
|
||||
async setActive(enteringView: RouteView) {
|
||||
async setActive(enteringView: RouteView): Promise<StackEvent> {
|
||||
let { direction, animation } = this.navCtrl.consumeTransition();
|
||||
const leavingView = this.activeView;
|
||||
if (isTabSwitch(enteringView, leavingView)) {
|
||||
const tabSwitch = isTabSwitch(enteringView, leavingView);
|
||||
if (tabSwitch) {
|
||||
direction = 'back';
|
||||
animation = undefined;
|
||||
}
|
||||
this.insertView(enteringView, direction);
|
||||
await this.transition(enteringView, leavingView, animation, this.canGoBack(1), false);
|
||||
requestAnimationFrame(() => this.cleanup());
|
||||
await this.cleanupAsync();
|
||||
return {
|
||||
enteringView,
|
||||
direction,
|
||||
animation,
|
||||
tabSwitch
|
||||
};
|
||||
}
|
||||
|
||||
canGoBack(deep: number, stackId = this.getActiveStackId()): boolean {
|
||||
@ -122,6 +129,15 @@ export class StackController {
|
||||
this.views = insertView(this.views, enteringView, direction);
|
||||
}
|
||||
|
||||
private cleanupAsync() {
|
||||
return new Promise(resolve => {
|
||||
requestAnimationFrame(() => {
|
||||
this.cleanup();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private cleanup() {
|
||||
const activeRoute = this.activeView;
|
||||
const views = this.views;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ComponentRef } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouterDirection } from '@ionic/core';
|
||||
import { NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
export function insertView(views: RouteView[], view: RouteView, direction: RouterDirection) {
|
||||
if (direction === 'root') {
|
||||
@ -44,7 +44,7 @@ export function getUrl(router: Router, activatedRoute: ActivatedRoute) {
|
||||
|
||||
export function isTabSwitch(enteringView: RouteView, leavingView: RouteView | undefined) {
|
||||
if (!leavingView) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return enteringView.stackId !== leavingView.stackId;
|
||||
}
|
||||
@ -80,6 +80,13 @@ export function destroyView(view: RouteView | undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface StackEvent {
|
||||
enteringView: RouteView;
|
||||
direction: RouterDirection;
|
||||
animation: NavDirection | undefined;
|
||||
tabSwitch: boolean;
|
||||
}
|
||||
|
||||
export interface RouteView {
|
||||
id: number;
|
||||
url: string;
|
||||
|
Reference in New Issue
Block a user