不要被術語嵌入包含所迷惑,下面用一個簡單的例子將它說明清楚。html
現有一個卡片組件(card component),它由header、body和footer三個部分組成。json
好比,咱們能夠這樣使用該組件:bootstrap
或者這樣:app
亦或者這樣佈局
總之很是方便。this
問題來了,咱們該如何實現**頭部和尾部格式固定,而body中的內容能夠動態顯示呢?
--答案是使用嵌入包含**。spa
transclusion是一個方法,容許你定義個固定視圖模板的同時,還能夠經過
<ng-content>
定義一個插槽,以顯示動態的內容。
頗有意思吧,下面咱們就來實現一下。code
|- 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'; }
組件模板template:component
<!-- card.component.html --> <div class="card"> <div class="card-header"> {{ header }} </div> <!-- single slot transclusion here --> <ng-content></ng-content> <div class="card-footer"> {{ footer }} </div> </div>
如今咱們已經定義好了一個組件,接下來咱們將使用它。orm
<!-- app.component.html --> <h1>Single slot transclusion</h1> <card header="my header" footer="my footer"> <!-- put your dynamic content here --> <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> <!-- end dynamic content --> <card>
最後在根模塊的declarations中聲明添加便可。
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { CardComponent } from './card.component'; // import card component @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, CardComponent ], // add in declaration bootstrap: [ AppComponent ], }) export class AppModule { }
好了,大功告成,保存並運行吧。div.card-block
中的內容將會代替<ng-content></ng-content>
。
<ng-content>
接受一個select
屬性,讓插槽具備選擇性。
<!-- card.component.html --> <div class="card"> <div class="card-header"> {{ header }} </div> <!-- add the select attribute to ng-content --> <ng-content select="[card-body]"></ng-content> <div class="card-footer"> {{ footer }} </div> </div>
注意,咱們添加了select=[card-body]
,這裏意思是「讓包含card-body
屬性的元素取代我」。
接着,在html中添加card-body
屬性。
<!-- app.component.html --> <h1>Single slot transclusion</h1> <card header="my header" footer="my footer"> <div class="card-block" card-body><!-- We add the card-body attribute here --> <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>
保存並運行,一切照常運行。
如今,若是移除card-body
,卡片body什麼也顯示不出來,那是由於咱們定義的<ng-content>
具備選擇性--只有帶有card-body
屬性的元素才能夠代替插槽。
<ng-content>
中select
屬性很是強大。舉幾個例子,
<!-- card.component.html --> ... <ng-content select="[card-type=body]"></ng-content> ...
card.component.html
... <ng-content select=".card-body"></ng-content> ...
app.component.html
... <div class="card-block card-body">...</div> ...
除此以外,例如select=[card][body]
,selector=".card.body"
card.component.html
... <ng-content select="card-body"></ng-content> ...
app.component.html
... <card-body class="card-block">...<card-body> ...
可是,你會遇到一個錯誤:Unhandled Promise rejection: Template parse errors: 'card-body' is not a known element。
Angular 2不認識card-body
標籤,它既不是指令,也不是組件。一個快速回避該錯誤的方法是:在模塊元數據中添加屬性schemas
,以下:
// 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 ] // add this line }) 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
<!-- 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>
咱們應該使用哪一個選擇器呢?屬性選擇器?html標籤?類選擇器?
視狀況而定。我更偏向於使用屬性選擇器,由於它更易讀。HTML標籤易讀但須要在元數據中添加schema
屬性。
應該儘量避免使用類選擇器,由於不直觀。你第一眼看到它時,第一反應不是「嵌入包含
」,除非你閱讀了組件的源碼。固然了,這都取決於你!
好了,就到這裏!祝coding愉快!