一、 ng-content 进行内容投影
 
1.1 ng-content
 
ng-content 元素是一个用来插入外部或者动态内容的占位符。父组件将外部内容传递给子组件,当 Angular 解析模板时,就会在子组件模板中 ng-content 出现的地方插入外部内容。
我们可以使用内容投影来创建可重用的组件。这些组件有相似的逻辑和布局,并且可以在许多地方使用。一般我们在封装一些公共组件的时候经常会用到。
1.2 为什么使用内容投影
定义一个 button 组件:
button-component.ts
@Component({
    selector: '[appButton]',
    template: `
    <span class="icon-search"></span>
`
})
export class AppButtonComponent {}
这个 button 组件的目的是在按钮内部加一个搜索的图标,我们实际使用如下:
<button appButton>
click
</button>
我们发现组件只会展示搜索图标, 按钮的文本不会展示,能你会想到最常使用的 @Input 装饰器,但是如果我们不只是想传文本进来,而是传一段 html 进来呢?此时就会用到 ng-content。
1.2 单插槽内容投影
内容投影的最基本形式是单插槽内容投影。
以 button 组件为例,创建一个单槽内容投影:
button-component.ts
@Component({
    selector: '[appButton]',
    template: `
    <span class="icon-search"></span> <ng-content></ng-content>
`
})
export class AppButtonComponent {}
实际使用如下:
<button appButton>
click
</button>
可以发现,现在这个 button 组件的效果是即显示了搜索图标,又显示了按钮的文本(click)。即把 <button appButton></button> 中间的内容 投影 到了组件的 <ng-content></ng-content> 位置。
1.3 多插槽内容投影
一个组件可以具有多个插槽,每个插槽可以指定一个 CSS 选择器,该选择器会决定将哪些内容放入该插槽。该模式称为多插槽内容投影。使用此模式,我们必须指定希望投影内容出现在的位置。可以通过使用 ng-content 的 select 属性来完成此任务。
- templateRefExp: ng-template元素的#ID
- contextExp: 
  - 可空参数
- content是一个对象,这个对象可以包含一个- $implicit的- key作为默认值, 使用时在- 模板中用- let-key语句进行绑定
- content的非默认字段需要使用- let-templateKey=contentKey语句进行绑定
 
使用如下:
@Component({
  selector: 'ng-template-outlet-example',
  template: `
    <ng-container *ngTemplateOutlet="greet"></ng-container>
    <hr>
    <ng-container *ngTemplateOutlet="eng; context: myContext"></ng-container>
    <hr>
    <ng-container *ngTemplateOutlet="svk; context: myContext"></ng-container>
    <hr>
    <ng-template #greet><span>Hello</span></ng-template>
    <ng-template #eng let-name><span>Hello {{name}}!</span></ng-template>
    <ng-template #svk let-person="localSk"><span>Ahoj {{person}}!</span></ng-template>
`
})
class NgTemplateOutletExample {
  myContext = {$implicit: 'World', localSk: 'Svet'};
}
2.5 利用 ngTemplateOutlet 进行内容投影
 
@Component({
    selector: 'app-card',
    template: `
		<div class="card">
		  <div class="header">
		  	<ng-container *ngTemplateOutlet="headerTemplate; context: { $implicit: title, index: otherDate }"></ng-container>
		  </div>
		</div>
`
})
export class AppCardComponent {
	 @ContentChild('header', { static: true }) headerTemplate: TemplateRef<any>;
	 public title = 'Test';
	 public otherDate = {
	 	auth: 'me',
	 	name: 'appCard'
	 };
}
使用
<app-card>
  <ng-template #header let-label let-item="otherDate">
    <h1>Angular</h1> {{label}} (Test) and  {{otherDate | json}} ({auth: 'me', name: 'appCard'})
  </ng-template>
</app-card>
参考
- Angular使用ng-content进行内容投影
- angular内容投影
- angular之ng-container 、ng-template的使用
- Angular 4.x NgTemplateOutlet










