Лучший способ установить разный макет для разных страниц в angular 4

Я новичок в angular 4. То, что я пытаюсь достичь, - это установить разные заголовки и нижние колонтитулы макетов для разных страниц в моем приложении. У меня три разных случая:

  • Вход, регистрация страницы (без заголовка, без нижнего колонтитула)

маршруты: ['login', 'register']

  1. Страница маркетингового сайта (это корневой путь и имеет верхний и нижний колонтитулы, в основном эти разделы идут до входа в систему)

маршруты: ['', 'about', 'contact']

  1. Приложение зарегистрировано на страницах (у меня есть другой верхний и нижний колонтитулы в этом разделе для всех страниц приложения, но этот верхний и нижний колонтитулы отличаются от заголовка и нижнего колонтитула маркетингового сайта)

routes: ['dashboard', 'profile']

Я запускаю приложение временно, добавляя верхний и нижний колонтитулы к компоненту html маршрутизатора.

Пожалуйста, посоветуйте мне лучший подход.

Это мой код:

Приложение \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>

приложение/дома/home.component.html

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

приложение/об/about.component.html

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

приложение/Логин/login.component.html

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

приложение/панель/dashboard.component.html

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

Я видел этот вопрос о переполнении стека, но я не получил четкого изображения из этого ответа

Ответ 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 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);

Ответ 2

вы можете использовать дочерний элемент, например.

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>

сообщение о раздельном в разных файлах маршрутах

Ответ 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 элемент ng-template

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

Включение именованных слотов

Вы можете создать app-header-main так, чтобы он использовал именованный слот transclusion

Внутри шаблона 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>

Ответ 4

Вы можете решить эту проблему, используя ng-content + ViewChild, вставляя макет в каждый компонент страницы, который использует этот конкретный макет.

Использование маршрутизатора для этого общего случая всегда казалось мне обходным путем. То, что вы хотите, похоже на макеты в Asp.Net MVC или MasterPages в WebForm и т.д.

После борьбы с этим у меня получилось что-то вроде этого:

см. рабочую демонстрацию: 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';
  }
}