因此,我有一个由面包屑,导航选项和功能即
组成的应用程序在上图中,“面包屑”和“选项”清晰可见,但是只要没有其他选项或子选项,功能组件就会加载或替换选项容器区域。
我的应用程序的目录结构如下,
下面的“操作和导航”文件夹包含以下文件,
下面是我编写的代码,
core.module.ts
import { NgModule } from '@angular/core';
import { FooterComponent } from './footer/footer.component';
import { HeaderComponent } from './header/header.component';
import { NavigationComponent } from './navigation/navigation.component';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PMRoutingModule } from '../router/pmrouter.module';
import { MatPaginatorModule,
MatSortModule,
MatTableModule,
MatFormFieldModule,
MatInputModule,
MatCheckboxModule,
MatButtonModule,
MatProgressSpinnerModule,
MatOptionModule,
MatSelectModule,
MatDialogModule,
MatAutocompleteModule,
MatRadioModule,
MatSnackBarModule,
MatDatepickerModule,
MatNativeDateModule} from '@angular/material';
import { ActionsListComponent } from './actions/actions-list.component';
import { ActionThumbnailComponent } from './actions/action-thumbnail.component';
@NgModule({
imports: [
CommonModule,
FormsModule,
BrowserAnimationsModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
MatFormFieldModule,
MatInputModule,
MatCheckboxModule,
MatButtonModule,
MatProgressSpinnerModule,
MatOptionModule,
MatSelectModule,
ReactiveFormsModule,
MatDialogModule,
MatAutocompleteModule,
MatRadioModule,
MatSnackBarModule,
MatDatepickerModule,
MatDatepickerModule,
MatNativeDateModule,
PMRoutingModule
],
declarations: [
HeaderComponent,
FooterComponent,
NavigationComponent,
ActionsListComponent,
ActionThumbnailComponent
],
exports: [
HeaderComponent,
FooterComponent,
NavigationComponent,
CommonModule,
FormsModule,
BrowserAnimationsModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
MatFormFieldModule,
MatInputModule,
MatCheckboxModule,
MatButtonModule,
MatProgressSpinnerModule,
MatOptionModule,
MatSelectModule,
ReactiveFormsModule,
MatDialogModule,
MatAutocompleteModule,
MatRadioModule,
MatSnackBarModule,
MatDatepickerModule,
MatDatepickerModule,
MatNativeDateModule,
PMRoutingModule
]
})
export class CoreModule { }
navigation.component.ts
import { Component, OnInit } from '@angular/core';
import { Params, ActivatedRoute, Router, NavigationEnd, PRIMARY_OUTLET } from '@angular/router';
import { filter } from 'rxjs/operators';
interface IBreadcrumb {
label: string;
params: Params;
url: string;
}
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
public breadcrumbs: IBreadcrumb[];
/**
* @class DetailComponent
* @constructor
*/
constructor(
private activatedRoute: ActivatedRoute,
private router: Router
) {
this.breadcrumbs = [];
}
/**
* Let's go!
*
* @class DetailComponent
* @method ngOnInit
*/
ngOnInit() {
const ROUTE_DATA_BREADCRUMB: string = "breadcrumb";
//subscribe to the NavigationEnd event
this.router.events.pipe(
filter(event => event instanceof NavigationEnd))
.subscribe(event => {
//set breadcrumbs
let root: ActivatedRoute = this.activatedRoute.root;
this.breadcrumbs = this.getBreadcrumbs(root);
});
}
/**
* Returns array of IBreadcrumb objects that represent the breadcrumb
*
* @class DetailComponent
* @method getBreadcrumbs
* @param {ActivateRoute} route
* @param {string} url
* @param {IBreadcrumb[]} breadcrumbs
*/
private getBreadcrumbs(route: ActivatedRoute, url: string='', breadcrumbs: IBreadcrumb[]=[]): IBreadcrumb[] {
const ROUTE_DATA_BREADCRUMB: string = "breadcrumb";
//get the child routes
let children: ActivatedRoute[] = route.children;
//return if there are no more children
if (children.length === 0) {
return breadcrumbs;
}
//iterate over each children
for (let child of children) {
console.log(child.url);
//verify primary route
if (child.outlet !== PRIMARY_OUTLET) {
continue;
}
//verify the custom data property "breadcrumb" is specified on the route
if (!child.snapshot.data.hasOwnProperty(ROUTE_DATA_BREADCRUMB)) {
return this.getBreadcrumbs(child, url, breadcrumbs);
}
//get the route's URL segment
let routeURL: string = child.snapshot.url.map(segment => segment.path).join("/");
//append route URL to URL
url += `/${routeURL}`;
//add breadcrumb
let breadcrumb: IBreadcrumb = {
label: child.snapshot.data[ROUTE_DATA_BREADCRUMB],
params: child.snapshot.params,
url: url
};
breadcrumbs.push(breadcrumb);
//recursive
return this.getBreadcrumbs(child, url, breadcrumbs);
}
}
}
navigation.component.html
<nav class="spacing">
<ol class="cd-breadcrumb triangle custom-icons">
<li *ngFor="let breadcrumb of breadcrumbs; let i = index" [ngClass]="breadcrumbs.length === (i + 1) ? 'current' : ''">
<div *ngIf="breadcrumbs.length === (i + 1);then last else parent"></div>
<ng-template #last>
<em>{{ breadcrumb.label }}</em>
</ng-template>
<ng-template #parent>
<a [routerLink]="breadcrumb.url">{{ breadcrumb.label }}</a>
</ng-template>
</li>
</ol>
</nav>
actions-list.component.ts
import { Component, OnInit } from '@angular/core';
import { Route, Router, NavigationEnd, ActivatedRoute, UrlSegment } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
templateUrl: './actions-list.component.html',
styleUrls: ['./actions-list.component.css']
})
export class ActionsListComponent implements OnInit {
rowActionClass: string[] = ['col-md-3 col-lg-2 col-sm-4 col-xs-6 card-short', 'col-md-3 col-lg-3 col-sm-4 col-xs-6 card-long'];
allRoutes = [] as Imenuoption[];
actions = [] as Imenuoption[];
errorMessage: string;
event = {} as NavigationEnd;
constructor(private router: Router) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd))
.subscribe(event => {
this.allRoutes = [];
this.getAllRoutes('', this.router.config);
this.setupActions();
});
}
ngOnInit(): void {
}
setupActions() {
this.actions = [];
const currentRoute: string[] = this.router.url.split('/');
for (let i = 0; i < this.allRoutes.length; i++) {
const str = this.allRoutes[i];
const rData: string[] = str.navURL.split('/');
if (this.router.url !== '/' && currentRoute.length === rData.length - 1 ) {
this.actions.push(this.allRoutes[i]);
}
}
}
getAllRoutes(parent: String, config: Route[]): Imenuoption[] {
for (let i = 0; i < config.length; i++) {
const route = config[i];
const option = {} as Imenuoption;
option.navURL = parent + '/' + route.path;
option.imageURL = option.navURL === '/' ? '' : route.data.imageURL;
option.description = option.navURL === '/' ? '' : route.data.breadcrumb;
this.allRoutes.push(option);
if (route.children) {
const currentPath = route.path ? parent + '/' + route.path : parent;
this.getAllRoutes(currentPath, route.children);
}
}
return this.allRoutes;
}
}
actions-list.component.html
<div class="row">
<div class="col-md-10 col-lg-10 col-md-offset-1 col-lg-offset-1">
<div class="row">
<ng-template ngFor let-actionCard="$implicit" [ngForOf]="actions">
<div [ngClass]="actions.length > 4 ? rowActionClass[0] : rowActionClass[1]">
<div *ngIf="actions.length > 4 ;then small else large"></div>
<ng-template #small>
<app-action-thumbnail [action]="actionCard" [cssCardHeight]="0"></app-action-thumbnail>
</ng-template>
<ng-template #large>
<app-action-thumbnail [action]="actionCard" [cssCardHeight]="1"></app-action-thumbnail>
</ng-template>
</div>
</ng-template>
</div>
</div>
</div>
action-thumbnail.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-action-thumbnail',
templateUrl: './action-thumbnail.component.html',
styleUrls: ['./action-thumbnail.component.css']
})
export class ActionThumbnailComponent implements OnInit {
@Input() action: Imenuoption;
@Input() cssCardHeight: number;
constructor() {
}
ngOnInit() {
}
}
action-thumbnail.component.html
<div *ngIf="cssCardHeight === 0;then small else large"></div>
<ng-template #large>
<div class="flip-card card-long" [routerLink]="action.navURL" routerLinkActive="router-link-active">
<div class="flip-card-inner text-center">
<div class="flip-card-front card-long" style="padding:20%">
<img class="img-responsive" [src]='action.imageURL' alt="Card image cap">
<br />
<h5 class="card-text" style="letter-spacing: 1px; color: black; font-size: 16px;">{{action.description}}</h5>
</div>
<div class="flip-card-back card-long">
<div class="card-body">
<h3 class="card-title" style="padding: 3%;">{{action.description}}</h3>
<h5 class="card-text">Description for this option goes here.</h5>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #small>
<div class="flip-card card-small" [routerLink]="action.navURL" routerLinkActive="router-link-active">
<div class="flip-card-inner text-center">
<div class="flip-card-front card-small" style="padding:20%">
<img class="img-responsive" [src]='action.imageURL' alt="Card image cap">
<br />
<h5 class="card-text" style="letter-spacing: 1px; color: black; font-size: 16px;">{{action.description}}</h5>
</div>
<div class="flip-card-back card-small">
<div class="card-body">
<h3 class="card-title" style="padding: 3%;">{{action.description}}</h3>
<h5 class="card-text">Description for this option goes here.</h5>
</div>
</div>
</div>
</div>
</ng-template>
router.ts
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full'},
{
path: 'home',
component: ActionsListComponent,
data : {
breadcrumb : 'Home'
},
children: [
{
path: 'settings',
component: ActionsListComponent,
data: {
breadcrumb: 'Settings',
imageURL: './assets/images/settings.png'
},
children: [
{
path: 'sub-option1',
component: OP1,
data: {
breadcrumb: 'Option 1',
imageURL: './assets/images/o1.png'
}
},
{
path: 'sub-option2',
component: Op2,
data: {
breadcrumb: 'Option 2',
imageURL: './assets/images/o2.png'
}
}]
},
{
path: 'o1',
component: Option1,
data: {
breadcrumb: 'option 1'
}
},
{
path: 'o2',
component: Option2,
data: {
breadcrumb: 'option 2'
}
},
{
path: 'o3',
component: Option3,
data: {
breadcrumb: 'option 3'
}
}]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class PMRoutingModule { }
我的问题,
使用上述结构,我无法决定将<router-outlet>
放置在何处以加载各个子选项或功能。