ng-content
ng-content vs ng-template
- 相同点
- 在组件之间传递模板
- 不同点
- Content 只能传递一层,不可以跨多层级组件传递。
- Content 可以理解为是实例,ngTemplate 可以理解为是类,也就是说 Content 只能是一个,template 可以传递给 ngFor,变多个。
- Content 我们更加可以理解为是 children,子 dom, template 完全没有这个限制,它就是某个模板,放到一个变量里面。
content 简介
抛出一个疑问,为什么,第一段话能看见,第二段话看不见。
<div>
<span>Hello I am Content</span>
</div>
<p-dropdown>
<span>Hello I am Content, But I am missing in DOM</span>
</p-dropdown>
定义:内容投影 (Content Projection),值将某个内容投影到其他的组件里面。
两个关键元素: 1. 投影的内容, 2. 投影的位置
- 投影的内容 (Content)值的是
<SomeComponent>I am Content</SomeComponent>
- 投影的位置 (Content Slot) 值的是
<ng-content></ng-content>
, 也就是说I am Content
会被投影到<ng-content></ng-content>
的位置。
内容投影的类别与使用场景
- 单槽位投影 (Single-slot content projection)
// 使用
<SomeComponent>I am Content</SomeComponent>
// SomeComponent 定义, I am Content 会被投影到下面
<ng-content></ng-content>
- 多槽位投影 (Multi-slot content projection) 也就说,组件内部可以同时接受多个 content 的投影,利用
ng-content
的select
参数来进行区别不同的内容。select 官方值的是css selector, 也就是说这个值是就是用的 css selector 的语法来定位元素的。
// SomeComponent 的使用
<SomeComponent>
<div content1>I am Content1</div>
<div content2>I am Content2</div>
<div content3>I am Content3</div>
</SomeComponent>
// SomeComponent 定义
...// befre dom
<ng-content select='[content1]'></ng-content>
<ng-content select='[content2]'></ng-content>
<ng-content select='[content3]'></ng-content>
...// after dom
// 最终的效果是
...// befre dom
<div content1>I am Content1</div>
<div content2>I am Content2</div>
<div content3>I am Content3</div>
...// after dom
介绍两个 primeng 两个很有意思的组件,我们经常会用到这两个.
<Panel>
<p-header>I am Header<p-header>
<p-footer>I am Footer</p-footer>
</Panel>
//其实在Panel 内部定义了这样的两个东西,此处省略若干行,
<ng-content select='p-header'></ng-content>
<ng-content select='p-footer'></ng-content>
@Component({
selector: "p-header",
template: "<ng-content></ng-content>",
})
export class Header {}
@Component({
selector: "p-footer",
template: "<ng-content></ng-content>",
})
export class Footer {}
为什么 Content 不能够传递多层
以下面这个结构来解释
//level1
<Com1>
<Com2></Com2>
</Com1>
// Com1 定义
<Panel>
<p-header>
<ng-content></ng-content>
</p-header>
</Panel>
// Com2 定义
<div>I am Content</div>
Angular 渲染的循序如下 这个顺序是完全没有问题的,可以相信。
- 在 level1 组件运行 CD, 更新 Com1, Com2 Inputs, 可能会调用他们的 ngonChanges.
- 对 Com2(而不是 Com1)运行 CD,
- 更新 Com1 中的 ContentChild, 也就是将 Com2 赋值给它,而对于 Com1 而言,由于它没有定义 ng-content, 所以,它应该没有地方可以赋值。注意,Com1 中的 ng-content 不属于 Com1, 而是属于 p-header 的。
- 然后更新 level1 的 Dom
- 接着对 Com1 运行 CD.
- 最后更新 level1 的 ViewChildren 引用。