【问题标题】:Best method to set different layout for different pages in angular 4在角度 4 中为不同页面设置不同布局的最佳方法
【发布时间】:2018-03-13 15:52:00
【问题描述】:

我是 Angular 4 的新手。我想要实现的是为我的应用程序中的不同页面设置不同的布局页眉和页脚。我有三种不同的情况:

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

路由:['login','register']

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

路线:['','about','contact']

  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>

我在 stack-overflow 上看到了 this question,但我没有从那个答案中得到清晰的画面

【问题讨论】:

标签: angular angular-routing angular-template angular-router


【解决方案1】:

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

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);

【讨论】:

  • Demo 帮助很大admin/profile,但由于它是空的,它匹配主 url 链接,如“/profile”,如果子路径也是路径:“”它匹配主页“”。也不太清楚这些组件到底是什么:组件,我只需将 留在原始组件中,并将所有内容发布到新生成的组件中。但是大 tnx :)
  • 延迟加载模块时如何使其工作??
  • @KarthikHande 即使在延迟加载时也能正常工作。 (我所有的作品都在延迟加载)。我会尝试制作一个加载模块的演示,但不能对此做出承诺。如果您仍然难以在延迟加载模块上实现此功能,请点击此处
  • 作为 Angular 的新手,@RameezRami 我很困惑,当上述两种布局都以 path: ' ' 空白路线开头时,浏览器将如何知道要走哪些路线。尽管它工作得很好,但你能解释一下吗
  • @AhsanAlii 简单来说,忘记浏览器是如何处理这个问题的。所有路线路径都通过角度解析。 {path: '',} 并不意味着路径在那里结束,它可以有子路径。但如果您使用{path: '',pathMatch: 'full',},则意味着您的路由级别的范围到此为止。尝试使用我分享的 stack-bits 演示,并通过将 pathMatch 移动到不同级别的路由定义来做一些实验。
【解决方案2】:

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

对我来说,将路由器用于这种常见用例似乎总是一种解决方法。您想要的类似于 Asp.Net MVC 中的 Layouts 或 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';
  }
}

【讨论】:

    【解决方案3】:

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

    输入和 css 类

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

    1. &lt;app-header-main [showUserTools]="false"&gt;&lt;/app-header-main&gt;

    1. &lt;app-header-main class="no-user-tools"&gt;&lt;/app-header-main&gt; 然后使用 :host(.no-user-tools) 显示/隐藏需要的内容

    1. 在路由级别(子级或非子级):

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

    并通过ActivatedRoute 访问它,如下所示:this.route.data.header.showUserTools

    模板参考输入

    app-header-main 组件内部:

    @Input() rightSide: TemplateRef&lt;any&gt;;

    TemplateRef&lt;any&gt; 类型的输入,您可以直接输入 ng-template 元素

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

    命名槽嵌入

    您可以创作 app-header-main 以便它使用命名插槽嵌入

    app-header-main 模板内部:

    &lt;ng-content select="[rightSide]"&gt;&lt;ng-content&gt;

    用法:

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

    【讨论】:

      【解决方案4】:

      你可以使用孩子例如

      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 将是“admin/dashboard”、“admin/profile”,我不希望这种情况发生..我想将 url 设置为“dashboard”、“profile” '。有什么办法吗?
      • 我想说,如果你有两个不同的页脚,你可以使用@input to 和 *ngIf 创建一个页脚来显示一个或另一个视图,或者制作两个页脚。无论如何,这只是一个例子。您可以将路径:'',组件:MainComponent,您的 DashboardComponent 和配置文件作为路径的“孩子”并忘记路径:admin
      • 如果您正在使用管理路由,它会很有帮助。谢谢你给我这个主意。
      • 如何覆盖 app-header-main 和 app-footer-main 的内容?
      猜你喜欢
      • 2014-10-22
      • 2017-10-13
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 1970-01-01
      • 2018-10-09
      • 1970-01-01
      相关资源
      最近更新 更多