mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
fix(angular): router-outlet animation
This commit is contained in:
@ -1,30 +1,32 @@
|
||||
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts } from '@angular/router';
|
||||
import * as ctrl from './router-controller';
|
||||
import { runTransition } from './router-transition';
|
||||
import { Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef, ElementRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET } from '@angular/router';
|
||||
|
||||
|
||||
@Directive({selector: 'ion-router-outlet', exportAs: 'ionOutlet'})
|
||||
@Directive({
|
||||
selector: 'ion-router-outlet',
|
||||
exportAs: 'outlet'
|
||||
})
|
||||
export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
|
||||
private activated: ComponentRef<any>|null = null;
|
||||
private deactivated: ComponentRef<any>|null = null;
|
||||
|
||||
private _activatedRoute: ActivatedRoute|null = null;
|
||||
private name: string;
|
||||
|
||||
private views: ctrl.RouteView[] = [];
|
||||
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
constructor(
|
||||
private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef,
|
||||
private resolver: ComponentFactoryResolver, @Attribute('name') name: string,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private elementRef: ElementRef,
|
||||
@Attribute('name') name: string,
|
||||
private changeDetector: ChangeDetectorRef) {
|
||||
this.name = name || 'primary';
|
||||
this.name = name || PRIMARY_OUTLET;
|
||||
parentContexts.onChildOutletCreated(this.name, this as any);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
ctrl.destoryViews(this.views);
|
||||
this.parentContexts.onChildOutletDestroyed(this.name);
|
||||
}
|
||||
|
||||
@ -82,36 +84,24 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute) {
|
||||
this.activated = ref;
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
ctrl.attachView(this.views, this.location, ref, activatedRoute);
|
||||
this.location.insert(ref.hostView);
|
||||
}
|
||||
|
||||
deactivate(): void {
|
||||
if (this.activated) {
|
||||
const c = this.component;
|
||||
|
||||
ctrl.deactivateView(this.views, this.activated);
|
||||
|
||||
this.deactivated = this.activated;
|
||||
this.activated = null;
|
||||
this._activatedRoute = null;
|
||||
this.deactivateEvents.emit(c);
|
||||
}
|
||||
}
|
||||
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
|
||||
async activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
|
||||
if (this.isActivated) {
|
||||
throw new Error('Cannot activate an already activated outlet');
|
||||
}
|
||||
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
const existingView = ctrl.getExistingView(this.views, activatedRoute);
|
||||
if (existingView) {
|
||||
// we've already got a view hanging around
|
||||
this.activated = existingView.ref;
|
||||
|
||||
} else {
|
||||
// haven't created this view yet
|
||||
const snapshot = (activatedRoute as any)._futureSnapshot;
|
||||
|
||||
const component = <any>snapshot.routeConfig !.component;
|
||||
@ -123,28 +113,39 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
|
||||
this.activated = this.location.createComponent(factory, this.location.length, injector);
|
||||
|
||||
// keep a ref
|
||||
ctrl.initRouteViewElm(this.views, this.activated, activatedRoute);
|
||||
}
|
||||
|
||||
// Calling `markForCheck` to make sure we will run the change detection when the
|
||||
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
|
||||
this.changeDetector.markForCheck();
|
||||
|
||||
const lastDeactivatedRef = ctrl.getLastDeactivatedRef(this.views);
|
||||
|
||||
runTransition(this.activated, lastDeactivatedRef).then(() => {
|
||||
console.log('transition end');
|
||||
await this.transition();
|
||||
this.activateEvents.emit(this.activated.instance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async transition() {
|
||||
const enteringRef = this.activated;
|
||||
const enteringEl = (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement;
|
||||
if (enteringEl) {
|
||||
enteringEl.classList.add('ion-page', 'hide-page');
|
||||
|
||||
const navEl = this.elementRef.nativeElement;
|
||||
navEl.appendChild(enteringEl);
|
||||
|
||||
await navEl.componentOnReady();
|
||||
await navEl.commit(enteringEl);
|
||||
|
||||
if (this.deactivated) {
|
||||
this.deactivated.destroy();
|
||||
this.deactivated = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OutletInjector implements Injector {
|
||||
constructor(
|
||||
private route: ActivatedRoute, private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector) {}
|
||||
private route: ActivatedRoute,
|
||||
private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector
|
||||
) {}
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === ActivatedRoute) {
|
||||
|
@ -21,7 +21,7 @@ const routes: Routes = [
|
||||
{ path: 'virtual-scroll', loadChildren: 'app/virtual-scroll/virtual-scroll.module#VirtualScrollModule' },
|
||||
|
||||
{ path: 'no-routing-nav', loadChildren: 'app/no-routing-nav/no-routing-nav.module#NoRoutingNavModule' },
|
||||
|
||||
{ path: 'simple-nav', loadChildren: 'app/simple-nav/simple-nav.module#SimpleNavModule' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -5,49 +5,49 @@
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href='show-hide-when'>Show/Hide When Test Page</a>
|
||||
<a [routerLink]="['/show-hide-when']">Show/Hide When Test Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='basic-inputs'>Basic Inputs Test Page</a>
|
||||
<a [routerLink]="['/basic-inputs']">Basic Inputs Test Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='group-inputs'>Group Inputs Test Page</a>
|
||||
<a [routerLink]="['/group-inputs']">Group Inputs Test Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='form-sample'>Form Sample Test Page</a>
|
||||
<a [routerLink]="['/form-sample']">Form Sample Test Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='alert'>Alert Page</a>
|
||||
<a [routerLink]="['/alert']">Alert Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='badge'>Badge Page</a>
|
||||
<a [routerLink]="['/badge']">Badge Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='card'>Card Page</a>
|
||||
<a [routerLink]="['/card']">Card Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='content'>Content Page</a>
|
||||
<a [routerLink]="['/content']">Content Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='actionSheet'>Action Sheet Page</a>
|
||||
<a [routerLink]="['/actionSheet']">Action Sheet Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='toast'>Toast Page</a>
|
||||
<a [routerLink]="['/toast']">Toast Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='loading'>Loading Page</a>
|
||||
<a [routerLink]="['/loading']">Loading Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='modal'>Modal Page</a>
|
||||
<a [routerLink]="['/modal']">Modal Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='popover'>Popover Page</a>
|
||||
<a [routerLink]="['/popover']">Popover Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='segment'>Segment Page</a>
|
||||
<a [routerLink]="['/segment']">Segment Page</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='virtual-scroll'>Virtual Scroll Page</a>
|
||||
<a [routerLink]="['/virtual-scroll']">Virtual Scroll Page</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -61,12 +61,6 @@
|
||||
<li>
|
||||
<a href='simple-nav/page-one'>Simple Nav</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='nested-nav/nested-page-one'>Nested Nav</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='nav-then-tabs/login'>Nav Then Tabs</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
14
demos/angular/src/app/simple-nav/page-one/page-one-routing.module.ts
Executable file
14
demos/angular/src/app/simple-nav/page-one/page-one-routing.module.ts
Executable file
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { PageOne } from './page-one';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: PageOne}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PageOneRoutingModule { }
|
17
demos/angular/src/app/simple-nav/page-one/page-one.module.ts
Executable file
17
demos/angular/src/app/simple-nav/page-one/page-one.module.ts
Executable file
@ -0,0 +1,17 @@
|
||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PageOne } from './page-one';
|
||||
import { PageOneRoutingModule } from './page-one-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageOneRoutingModule
|
||||
],
|
||||
declarations: [PageOne],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
]
|
||||
})
|
||||
export class PageOneModule { }
|
28
demos/angular/src/app/simple-nav/page-one/page-one.ts
Executable file
28
demos/angular/src/app/simple-nav/page-one/page-one.ts
Executable file
@ -0,0 +1,28 @@
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { PageTwo } from '../page-two/page-two';
|
||||
|
||||
@Component({
|
||||
selector: 'page-one',
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Simple Page One</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
Page One - {{ts}}
|
||||
<div>
|
||||
<ion-button [routerLink]="['/simple-nav/page-two']">Go to Page Two</ion-button>
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class PageOne {
|
||||
|
||||
ts: number;
|
||||
constructor() {
|
||||
setInterval(() => {
|
||||
this.ts = Date.now();
|
||||
}, 500);
|
||||
}
|
||||
}
|
14
demos/angular/src/app/simple-nav/page-three/page-three-routing.module.ts
Executable file
14
demos/angular/src/app/simple-nav/page-three/page-three-routing.module.ts
Executable file
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { PageThree } from './page-three';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: PageThree }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PageThreeRoutingModule { }
|
19
demos/angular/src/app/simple-nav/page-three/page-three.module.ts
Executable file
19
demos/angular/src/app/simple-nav/page-three/page-three.module.ts
Executable file
@ -0,0 +1,19 @@
|
||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PageThree } from './page-three';
|
||||
import { PageThreeRoutingModule } from './page-three-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageThreeRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
PageThree
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
]
|
||||
})
|
||||
export class PageThreeModule { }
|
40
demos/angular/src/app/simple-nav/page-three/page-three.ts
Executable file
40
demos/angular/src/app/simple-nav/page-three/page-three.ts
Executable file
@ -0,0 +1,40 @@
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'page-three',
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Page Three</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
Page Three {{ts}}
|
||||
<div>isProd: {{isProd}}</div>
|
||||
<div>paramOne: {{paramOne}}</div>
|
||||
<div>paramTwo: {{paramTwo}}</div>
|
||||
<div>
|
||||
<ion-button>Go Back</ion-button>
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class PageThree {
|
||||
|
||||
ts: number;
|
||||
isProd = false;
|
||||
paramOne: any = null;
|
||||
paramTwo: any = null;
|
||||
|
||||
// constructor(private navController: NavController, private navParams: NavParams) {
|
||||
|
||||
// this.isProd = navParams.get('isProd');
|
||||
// this.paramOne = navParams.get('paramOne');
|
||||
// this.paramTwo = navParams.get('paramTwo');
|
||||
|
||||
// setInterval(() => {
|
||||
// this.ts = Date.now();
|
||||
// }, 500);
|
||||
// }
|
||||
|
||||
}
|
17
demos/angular/src/app/simple-nav/page-two/page-two-routing.module.ts
Executable file
17
demos/angular/src/app/simple-nav/page-two/page-two-routing.module.ts
Executable file
@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { PageTwo } from './page-two';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PageTwo,
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PageTwoRoutingModule { }
|
25
demos/angular/src/app/simple-nav/page-two/page-two.module.ts
Executable file
25
demos/angular/src/app/simple-nav/page-two/page-two.module.ts
Executable file
@ -0,0 +1,25 @@
|
||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import {
|
||||
IonicAngularModule,
|
||||
} from '@ionic/angular';
|
||||
|
||||
import { PageTwo } from './page-two';
|
||||
import { PageTwoRoutingModule } from './page-two-routing.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PageTwoRoutingModule,
|
||||
IonicAngularModule,
|
||||
],
|
||||
declarations: [
|
||||
PageTwo,
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
]
|
||||
})
|
||||
export class PageTwoModule { }
|
26
demos/angular/src/app/simple-nav/page-two/page-two.ts
Executable file
26
demos/angular/src/app/simple-nav/page-two/page-two.ts
Executable file
@ -0,0 +1,26 @@
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'page-two',
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Page Two</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
Page Two - {{ts}}
|
||||
<div>
|
||||
<ion-button>Go to Page Three</ion-button>
|
||||
</div>
|
||||
<div>
|
||||
<ion-button>Go Back</ion-button>
|
||||
</div>
|
||||
</ion-content>
|
||||
`
|
||||
})
|
||||
export class PageTwo {
|
||||
|
||||
}
|
22
demos/angular/src/app/simple-nav/simple-nav-routing.module.ts
Executable file
22
demos/angular/src/app/simple-nav/simple-nav-routing.module.ts
Executable file
@ -0,0 +1,22 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { SimpleNavPageComponent } from './simple-nav.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: SimpleNavPageComponent,
|
||||
children: [
|
||||
{ path: 'page-one', loadChildren: './page-one/page-one.module#PageOneModule' },
|
||||
{ path: 'page-two', loadChildren: './page-two/page-two.module#PageTwoModule' },
|
||||
{ path: 'page-three/:paramOne/:paramTwo', loadChildren: './page-three/page-three.module#PageThreeModule', data: { isProd: true} }
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class SimpleNavRoutingModule { }
|
11
demos/angular/src/app/simple-nav/simple-nav.component.ts
Executable file
11
demos/angular/src/app/simple-nav/simple-nav.component.ts
Executable file
@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-page',
|
||||
template: `
|
||||
<ion-app>
|
||||
<ion-router-outlet></ion-router-outlet>
|
||||
</ion-app>
|
||||
`
|
||||
})
|
||||
export class SimpleNavPageComponent {}
|
20
demos/angular/src/app/simple-nav/simple-nav.module.ts
Executable file
20
demos/angular/src/app/simple-nav/simple-nav.module.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
|
||||
import { SimpleNavPageComponent } from './simple-nav.component';
|
||||
import { SimpleNavRoutingModule } from './simple-nav-routing.module';
|
||||
|
||||
import { IonicAngularModule } from '@ionic/angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
SimpleNavPageComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicAngularModule,
|
||||
SimpleNavRoutingModule
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class SimpleNavModule {}
|
Reference in New Issue
Block a user