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

Posted

技术标签:

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

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

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

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

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

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

    应用登录页面(我在此部分中为所有应用页面设置了不同的页眉和页脚,但此页眉和页脚与营销网站页眉和页脚不同)

路线:['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,但我没有从那个答案中得到清晰的画面

【问题讨论】:

这个链接有几种方法可以做到这一点:blog.angularindepth.com/… 【参考方案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 类来控制共享元素的内部外观,例如:

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

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

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

    
      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 的内容?

以上是关于在角度 4 中为不同页面设置不同布局的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

页面布局方案

如何在 Kendo UI Grid 中为不同的页面设置不同的页面大小

不同屏幕尺寸的标签系列自动布局? [关闭]

在 Django 中为多个查询编写视图的最佳方法?

如何在 cakephp 中为不同的模型设置不同的布局

比较具有相同数据但标记不同的两个 HTML 页面的最佳方法是啥