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-contentselect参数来进行区别不同的内容。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 引用。
posted @ 2021-11-26 13:44  kongshu  阅读(117)  评论(0编辑  收藏  举报