iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 14
1
Modern Web

Angular 2 之 30 天邁向神乎其技之路系列 第 14

[Day 14] Angular 2 + <ng-content> 嵌入式設計靈活組織 HTML

前言

嵌入式設計就是將 B 的內容嵌入進去 A ,A 文件中預留一個空間就是留給 B 放東西用的。大概就長這樣:

好處跟模板類似,可以在做設計時有更明確的邏輯,有些地方我們不會去更動,而要更動的地方就用嵌入的方式放進去,如此一來整體文件看起來自然會比較簡潔,而嵌入的部分獨立出來之後也好維護。

藍圖

我們將設計一個中間內容可以嵌入的卡片 Component 來展示嵌入的效果,可以先看看成果: Plunker

|- app/
    |- app.component.html
    |- app.component.ts
    |- app.module.ts
    |- card.component.ts
    |- card.component.html
    |- main.ts
|- index.html
|- systemjs.config.js
|- tsconfig.json

動工囉

卡片組件

一個卡片分為:頭、身體、腳。我們將把身體變成嵌入的。

// card.component.ts

import { Component, Input, Output } from '@angular/core';
@Component({
  selector: 'card',
  templateUrl: 'card.component.html',
})
export class CardComponent {
    @Input() header: string = 'this is header';   
    @Input() footer: string = 'this is footer';
}

@Input()代表可以從 parent 傳給 child。

卡片模板

<!-- card.component.html -->

<div class="card">
    <div class="card-header">
        {{ header }}
    </div>

    <!-- 單一嵌入點 -->
    <ng-content></ng-content>

    <div class="card-footer">
        {{ footer }}
    </div>
</div>

<ng-content>就是我們嵌入東西的地方。

使用

接著我們就可以在其他地方使用卡片了

<!-- app.component.html -->

<h1>Single slot transclusion</h1>
<card header="my header" footer="my footer">
  <!-- 放入要嵌入的動態內容 -->
  <div class="card-block">
    <h4 class="card-title">You can put any content here</h4>
    <p class="card-text">For example this line of text and</p>
    <a href="#" class="btn btn-primary">This button</a>
  </div>
  <!-- 結束 -->
<card>

我們可以在 AppComponent 直接使用 card<card> 裡面放入我們要的內容,就會自己嵌入進 card 了。

App Module

記得設定 app module

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';
import { CardComponent } from './card.component'; // 記得加入

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, CardComponent ], // 注入
  bootstrap:    [ AppComponent ],
})

export class AppModule { }

其他方法

  • 可以透過 Atrribute
<!-- card.component.html -->
...
<!--  ng-content 中加入 select attribute  -->
<ng-content select="[card-body]"></ng-content>
...
<!-- app.component.html -->
<card header="my header" footer="my footer">
    <div class="card-block" card-body><!--  增加 card-body 屬性 -->
    ...
    </div>
<card>
  • 可以透過 attribute with value
<!-- card.component.html -->
...
<ng-content select="[card-type=body]"></ng-content>
...
<!-- app.component.html -->
...
<div class="card-block" card-type="body">...<div>
...
  • 也可以透過 class
<!-- card.component.html -->
...
<ng-content select=".card-body"></ng-content>
...
<!-- app.component.html -->
...
<div class="card-block card-body">...</div>
...
  • 當然也可以同時有多個 Atrribute 或 CSS Class
<!-- card.component.html -->
...
<ng-content select="[card][body]"></ng-content>
...
<!-- app.component.html -->
...
<div class="card-block" body card>...</div>
...
  • HTML Tag 也可以,但要多設定一些東西
<!-- card.component.html -->
...
<ng-content select="card-body"></ng-content>
...
<!-- app.component.html -->
...
<card-body class="card-block">...<card-body>
...

這邊要設定 NO_ERRORS_SCHEMA,不然會出錯

// app.module.ts

import { NgModule, NO_ERRORS_SCHEMA }      from '@angular/core'; //
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }   from './app.component';
import { CardComponent } from './card.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, CardComponent ],
  bootstrap:    [ AppComponent ],
  schemas:      [ NO_ERRORS_SCHEMA ] // 增加這行
})

export class AppModule { }

多點嵌入

除了單一點嵌入,多點嵌入當然也可以

<!-- card.component.html -->

<div class="card">
    <div class="card-header">
    <!-- header slot here -->
        <ng-content select="card-header"></ng-content>
    </div>
    <!-- body slot here -->
    <ng-content select="card-body"></ng-content>
    <div class="card-footer">
    <!-- footer -->
        <ng-content select="card-footer"></ng-content>
    </div>
</div>
<!-- app.component.html -->

<h1>Multi slot transclusion</h1>
<card>
    <!-- header -->
    <card-header>
        New <strong>header</strong>
    </card-header>

    <!-- body -->
    <card-body>
        <div class="card-block">
            <h4 class="card-title">You can put any content here</h4>
            <p class="card-text">For example this line of text and</p>
            <a href="#" class="btn btn-primary">This button</a>
          </div>
    </card-body>

    <!-- footer -->
    <card-footer>
        New <strong>footer</strong>
    </card-footer>
<card>

總結

哪一種嵌入方式最好呢?其實單看大家喜好囉!只是如果用 Atrribute 和 HTML Tag 對於閱讀程式碼來說是最友善的,但是 Tag 又必須多加設定,其實有點麻煩,最佳選擇應該就是 Atrribute 了 XD


上一篇
[Day 13] Angular 2 多語言 ( 2 )
下一篇
[Day 15] Angular 2 Module ( 1 )
系列文
Angular 2 之 30 天邁向神乎其技之路31

尚未有邦友留言

立即登入留言