在angular 4中为不同页面设置不同布局的最佳方法


76

我刚接触angular4。我想要实现的是为应用程序中的不同页面设置不同的布局页眉和页脚。我有三种不同的情况:

  1. 登录,注册页面(无页眉,无页脚)

路线:['登录','注册']

  1. 营销站点页面(这是根路径,并且具有页眉和页脚,大多数这些部分在登录之前出现)

路线:['','关于','联系']

  1. 应用程序登录页面(本节中所有应用程序页面的页眉和页脚都有不同,但是此页眉和页脚与营销网站的页眉和页脚不同)

路线:['dashboard','profile']

我通过在路由器组件html中添加页眉和页脚来临时运行该应用程序。

请告诉我一个更好的方法。

这是我的代码:

app \ app.routing.ts

   const appRoutes: Routes = [
        { path: '', component: HomeComponent},
        { path: 'about', component: AboutComponent},
        { path: 'contact', component: ContactComponent},
        { path: 'login', component: LoginComponent },
        { path: 'register', component: RegisterComponent },
        { path: 'dashboard', component: DashboardComponent },
        { path: 'profile', component: ProfileComponent },


        // otherwise redirect to home
        { path: '**', redirectTo: '' }
    ];

    export const routing = RouterModule.forRoot(appRoutes);

app.component.html

<router-outlet></router-outlet>

app / home / home.component.html

<site-header></site-header>
<div class="container">
    <p>Here goes my home html</p>
</div>
<site-footer></site-footer>

app / about / about.component.html

<site-header></site-header>
<div class="container">
    <p>Here goes my about html</p>
</div>
<site-footer></site-footer>

app / login / login.component.html

<div class="login-container">
    <p>Here goes my login html</p>
</div>

app / dashboard / dashboard.component.html

<app-header></app-header>
<div class="container">
    <p>Here goes my dashboard html</p>
</div>
<app-footer></app-footer>

我在堆栈溢出中看到了这个问题,但是从该答案中我没有得到清晰的画面


此链接有几个方法可以做到这一点:blog.angularindepth.com/...
Rakeshk Khanapure

Answers:


150

您可以使用子路由解决您的问题。

https://angular-multi-layout-example.stackblitz.io/上查看工作演示,或在https://stackblitz.com/edit/angular-multi-layout-example上进行编辑

像下面这样设置您的路线

const appRoutes: Routes = [
    
    // Site routes goes here 
    { 
        path: '', 
        component: SiteLayoutComponent,
        children: [
          { path: '', component: HomeComponent, pathMatch: 'full'},
          { path: 'about', component: AboutComponent }
        ]
    },
    
    // App routes goes here
    { 
        path: '',
        component: AppLayoutComponent, 
        children: [
          { path: 'dashboard', component: DashboardComponent },
          { path: 'profile', component: ProfileComponent }
        ]
    },

    // no layout routes
    { path: 'login', component: LoginComponent},
    { path: 'register', component: RegisterComponent },
    // otherwise redirect to home
    { path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(appRoutes);

5
演示确实起了很大的作用,我很难理解这一点,主要是我无法获得空的路径:”的意思是,如果存在路径:“ admin”生成的链接将与admin / profile匹配,但由于其为空它匹配主网址链接(例如“ / profile”),并且如果子路径也是路径:“则匹配首页”。还不清楚这些组件到底是什么:组件,我只需要将<router-outlet> </ router-outlet>保留在原始组件中,然后将所有内容发布到新生成的组件中。但是很大的tnx :)
Jiro Matchonson

1
感谢您的回答。它清除了我遇到的一个问题,其中我的布局组件有一个命名路由器,这引起了各种各样的问题。只需将其删除即可使所有工作按预期进行。
meteorainer

1
非常感谢@Rameez
Srinivas'1

延迟加载模块时如何使这项工作?
ksh

1
@AhsanAlii简而言之,忘记浏览器如何处理它。所有路径均按角度解析。{path: '',}并不意味着路径到此结束,它可以具有子路径。但是,如果您使用{path: '',pathMatch: 'full',}它,则意味着路由级别的范围就此结束。尝试玩我共享的堆栈位演示,并通过移动pathMatch到不同级别的路由定义进行一些实验。
拉米兹·拉米

10

你可以用孩子

const appRoutes: Routes = [
    { path: '', component: MainComponent,
        children:{
            { path: 'home'  component:HomeComponent},
            { path: 'about', component: AboutComponent},
            { path: 'contact', component: ContactComponent},
               ..others that share the same footer and header...

        }
    },
    { path: 'login', component: LoginComponent },
    { path: 'register', component: RegisterComponent },
    { path: 'admin', component:AdminComponent, 
         children{
            { path: 'dashboard', component: DashboardComponent },
            { path: 'profile', component: ProfileComponent }
               ..others that share the same footer and header...
         }
    }
    { path: '**', redirectTo: '' }
];

MainComponent和AdminComponent一样

<app-header-main></app-header-main>
<router-outlet></router-outlet>
<app-footer-main></app-footer-main>

帖子中讨论了在不同文件中分开的路由


根据答案的URL将是“管理员/仪表板”,“管理员/配置文件”,我不希望这种情况发生..我想将URL设置为“仪表板”,“配置文件”。有什么办法吗?
ninja dev

我想说的是,如果您有两个不同的页脚,则可以使用@input到* ngIf来显示一个或另一个视图,或者制作两个页脚。无论如何,这只是一个例子。您可以将路径“'',“ component:MainComponent,您的DashboardComponent和配置文件”作为“子代”,而忽略路径:admin
Eliseo

如果您想了解管理路线,则对您有帮助。谢谢你给我这个主意。
Gurpreet Singh '18

1
如何覆盖app-header-main和app-footer-main的内容?
Ievgen Naida

3

在某些情况下,布局和共享元素实际上与路由结构不匹配,或者某些元素必须根据每个路由隐藏/显示。对于这种情况,我可以考虑以下策略(下面以app-header-main组件为例-显然,它将应用于任何共享页面元素):

输入和CSS类

您可以提供输入或CSS类来控制共享元素的内部外观,例如:

  1. <app-header-main [showUserTools]="false"></app-header-main>

要么

  1. <app-header-main class="no-user-tools"></app-header-main> 然后使用:host(.no-user-tools)显示/隐藏需要

要么

  1. 在路由级别(是否为子级):

    {
      path: 'home',
      component: HomeComponent,
      data: {
        header: {showUserTools: true},
      },
    },
    

并通过ActivatedRoute如下方式访问它:this.route.data.header.showUserTools

TemplateRef输入

内部app-header-main组件:

@Input() rightSide: TemplateRef<any>;

TemplateRef<any>您可以ng-template直接输入元素的类型输入

<app-header-main [rightSide]="rightside"></app-header-main>
<ng-template #rightside>your content here</ng-template>

命名时隙包含

您可以创作app-header-main,以便它使用命名的插槽转换

在app-header-main模板内部:

<ng-content select="[rightSide]"><ng-content>

用法:

<app-header-main class="no-user-tools">
  <div rightSide>your content here</div>
</app-header-main>

0

您可以使用ng-content + ViewChild将布局注入使用该特定布局的每个页面组件中来解决该问题。

在我看来,将路由器用于这种常见用例似乎总是一种解决方法。您想要的类似于Asp.Net MVC中的Layout或WebForm等中的MasterPages。

在为此苦苦挣扎之后,我得到了这样的结果:

参见工作演示:https : //stackblitz.com/edit/angular-yrul9f

shared.component-layout.ts

import { Component } from '@angular/core';

@Component({
  selector: 'shared-component-layout',
  template: `
  <div *ngIf="!hideLayoutHeader" style="font-size: 2rem;margin-bottom: 10px;">
    Layout title: {{layoutHeader}}
    <ng-content select=".layout-header">    
    </ng-content>
  </div>
  <ng-content select=".layout-body">
  </ng-content>
  `
})
export class SharedComponentLayout {
  layoutHeader: string;
  hideLayoutHeader: boolean;
}

page.component-base.ts

import { Component, ViewChild } from '@angular/core';
import { SharedComponentLayout } from './shared.component-layout';

export abstract class PageComponentBase {
    @ViewChild('layout') protected layout: SharedComponentLayout;
}

login.component.ts-不带标题

import { Component } from '@angular/core';
import { PageComponentBase } from './page.component-base';

@Component({
  selector: 'login-component',
  template: `
  <shared-component-layout #layout>
    <div class="layout-body">
      LOGIN BODY
    </div>
  </shared-component-layout>
  `
})
export class LoginComponent extends PageComponentBase {

  ngOnInit() {
    this.layout.hideLayoutHeader = true;    
  }
}

home.component.ts-带标题

import { Component } from '@angular/core';
import { PageComponentBase } from './page.component-base';

@Component({
  selector: 'home-component',
  template: `
  <shared-component-layout #layout>
    <div class="layout-body">
      HOME BODY
    </div>
  </shared-component-layout>
  `
})
export class HomeComponent extends PageComponentBase {

  ngOnInit() {    
    this.layout.layoutHeader = 'Home component header';
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.