实际开发过程的场景
在实际开发过程中,会遇到讲一个DOM 作为一个Input传给子组件,然后在子组件投影渲染出来。
- 子组件设置默认投影
- 子组件设置多个投影
- 在父组件中使用投影中的上下文内容
具体实现
创建两个组件,一个父组件ContentShadowUseComponent
,一个子组件ContentShadowComponent
子组件设置默认投影
- 在子组件
ContentShadowComponent
中设置单插槽投影,可以使用<ng-content></ng-content>
<h3>内容投影</h3>
<h4>默认内容投影</h4>
<ng-content></ng-content>
- 在父组件
ContentShadowUseComponent
使用:
<app-content-shadow>
默认的投影内容 - used
</app-content-shadow>
这种使用方式,即在父组件中使用的子组件中,所有的DOM都属于投影内容,在子组件设置
<ng-content></ng-content>
全部渲染出来,这里的<ng-content></ng-content>
只是占位符,元素本身不会创建DOM
子组件从父组件传入的变量进行投影
- 在子组件
ContentShadowComponent
的类文件中定义一个变量
import {Component, Input, OnInit, TemplateRef} from '@angular/core';
@Component({
selector: 'app-content-shadow',
templateUrl: './content-shadow.component.html',
styleUrls: ['./content-shadow.component.less']
})
export class ContentShadowComponent implements OnInit {
@Input() inputContainer: TemplateRef<void>;
constructor() {
}
ngOnInit(): void {
}
}
- 在子组件
ContentShadowComponent
的模版文件中使用此变量
<h4>@Input投影</h4>
<ng-container *ngTemplateOutlet="inputContainer"></ng-container>
- 在父组件
ContentShadowUseComponent
中使用子组件
<app-content-shadow [inputContainer]="inputContainer">
默认的投影内容 - used
</app-content-shadow>
<ng-template #inputContainer>
inputContainer的投影内容 ~~~ -- used
</ng-template>
这个时候,DOM
inputContainer的投影内容 ~~~ -- used
会在子组件的<ng-container *ngTemplateOutlet="inputContainer"></ng-container>
处投影,多使用于按条件投影。
多个插槽的投影
- 在子组件
ContentShadowComponent
的模版文件中,给ng-content
标签添加一个select
属性,select
属性支持签名、属性、CSS 类和 :not 伪类的任意组合。
<h4>多个插槽投影</h4>
<ng-content select="[concept]"></ng-content>
这里是给
ng-content
添加了一个属性为concept
,即在使用过程中,带有属性concept
会投影在这个ng-content
中
- 在父组件
ContentShadowUseComponent
使用
<app-content-shadow [inputContainer]="inputContainer">
默认的投影内容 - used
<p concept>
多个投影的内容 -- used
</p>
</app-content-shadow>
在父组件中使用投影中的上下文内容
- 在父组件中使用投影中的默认的上下文内容
- 修改子组件的模版文件
<h3>内容投影</h3>
<h4>默认内容投影</h4>
<ng-content></ng-content>
<nz-divider></nz-divider>
<h4>多个插槽投影</h4>
<ng-content select="[concept]"></ng-content>
<nz-divider></nz-divider>
<h4>@Input投影</h4>
<ng-container *ngTemplateOutlet="inputContainer"></ng-container>
<nz-divider></nz-divider>
<h4>@Input投影添加上下文</h4>
<ng-container *ngTemplateOutlet="inputContainerContext;context: containerContext"></ng-container>
- 在子组件中定义变量
containerContext
import {Component, Input, OnInit, TemplateRef} from '@angular/core';
@Component({
selector: 'app-content-shadow',
templateUrl: './content-shadow.component.html',
styleUrls: ['./content-shadow.component.less']
})
export class ContentShadowComponent implements OnInit {
@Input() inputContainer: TemplateRef<void>;
@Input() inputContainerContext: TemplateRef<void>;
public containerContext = {
$implicit: 'ContentShadow: 默认的投影上下文 --- 默认的投影上下文',
};
constructor() {
}
ngOnInit(): void {
}
}
- 在父组件中使用
<app-content-shadow [inputContainer]="inputContainer"
[inputContainerContext]="inputContainerContext">
默认的投影内容 - used
<p concept>
多个投影的内容 -- used
</p>
</app-content-shadow>
<ng-template #inputContainer>
inputContainer的投影内容 ~~~ -- used
</ng-template>
<ng-template #inputContainerContext let-content>
带有上下文的投影,上下文为: {{content}} -- used
</ng-template>
这里在父组件中就可以使用来自子组件的上下文内容了
- 在父组件中使用投影中的其他的上下文内容
- 修改子组件的模版文件
<h3>内容投影</h3>
<h4>默认内容投影</h4>
<ng-content></ng-content>
<nz-divider></nz-divider>
<h4>多个插槽投影</h4>
<ng-content select="[concept]"></ng-content>
<nz-divider></nz-divider>
<h4>@Input投影</h4>
<ng-container *ngTemplateOutlet="inputContainer"></ng-container>
<nz-divider></nz-divider>
<h4>@Input投影添加上下文</h4>
<ng-container *ngTemplateOutlet="inputContainerContext;context: containerContext"></ng-container>
<nz-divider></nz-divider>
<h4>@Input投影添加其他上下文</h4>
<ng-container *ngTemplateOutlet="inputContainerContextOther;context: containerContext"></ng-container>
<nz-divider></nz-divider>
- 修改子组件中定义变量
containerContext
import {Component, Input, OnInit, TemplateRef} from '@angular/core';
@Component({
selector: 'app-content-shadow',
templateUrl: './content-shadow.component.html',
styleUrls: ['./content-shadow.component.less']
})
export class ContentShadowComponent implements OnInit {
@Input() inputContainer: TemplateRef<void>;
@Input() inputContainerContext: TemplateRef<void>;
@Input() inputContainerContextOther: TemplateRef<void>;
public containerContext = {
$implicit: 'ContentShadow: 默认的投影上下文 --- 默认的投影上下文',
otherContext: 'ContentShadow: 其他的投影上下文 -- -- -- 其他的投影上下文'
};
constructor() {
}
ngOnInit(): void {
}
}
- 在父组件中使用
<app-content-shadow [inputContainer]="inputContainer"
[inputContainerContext]="inputContainerContext"
[inputContainerContextOther]="inputContainerContextOther">
默认的投影内容 - used
<p concept>
多个投影的内容 -- used
</p>
</app-content-shadow>
<ng-template #inputContainer>
inputContainer的投影内容 ~~~ -- used
</ng-template>
<ng-template #inputContainerContext let-content>
带有上下文的投影,上下文为: {{content}} -- used
</ng-template>
<ng-template #inputContainerContextOther let-content="otherContext">
带有上下文的投影,上下文为: {{content}} -- used
</ng-template>
这里使用
let-content="otherContext"
来确定使用来自子组件上下文中的otherContext
变量