本文会蕴含作者一些了解,为了不和原作者意思混同,会将集体的了解放在【】里。
原文地址
那是我忙于为我的办公我的项目创作新性能的日子之一。忽然间,某些事件引起了我的留神。
上图是angular最终渲染进去的DOM
当我审查DOM时候,我看到这个 ngcontent
被Angular利用到了元素上。如果他们蕴含元素在最终的DOM里,那么<ng-container>
是用来干什么的? 那是我很困惑在 <ng-container>
和 <ng-content>
中。
在探寻问题答案的时候我发现了<ng-template>
和 *ngTemplateOutlet
的概念。当初咱们有四个听起来简直雷同的概念。我开始了探寻它们的旅程。
你已经也遇到过这种状况吗?如果是,那么你来对中央了。闲话少说,让咱们一个一个来解说他们。
1. < ng-template >
顾名思义,<ng-template>
是一个模板元素,用于Angular与构造指令联合应用(*ngIf
, *ngFor
, [ngSwitch]
和自定义指令)
<font color='red'>这些模板元素仅工作在构造指令存在的时候</font>。Angular包装了咱们利用指令的元素。 思考下边的一个*ngIf
的例子。
【咱们能够看到,在一个一般元素上增加构造指令,angular在解析时候,其实会帮我买创立一个ng-template元素,并将相干的构造指令放到ng-template上进行解决】
下面展现的是Angular对与*ngIf
的解释。 最终的DOM与咱们在本文结尾看到的相似。
应用办法
咱们曾经看到了Angular应用<ng-template>
的形式。然而咱们如何应用它呢?因为它只和构造指令一起工作,所以咱们能够这样应用:【这种是❌形式,后边会讲到】
此处的 home
设置为 true
, 上述代码在DOM中的输入为:
什么都没有被渲染进去!这是为什么呢? 其实,这正是预期的后果。正如咱们曾经探讨过的,Angular会用正文代替ng-template
【译文应用的Angular版本为6.1.10。 在Angular12版本,曾经用非凡的className代替正文了】,咱们的代码最终会被解释成如下代码。
咱们的<ng-template>
在被Angular包装之后,变成了两个。然而无论怎样,Angular都不对<ng-template>
的内容进行选中。
以下是两种<font color=green>正确</font>的应用形式:
Method 1
在第一种办法中,你提供给Angular一种不须要进一步解决的形式。这样Angular将仅仅转换 <ng-template>
到正文里,并不会扭转其内容。(它们不会再像之前的例子一样被放在任何<ng-template>
中)。因而,它将正确的渲染内容。
要想理解更多如何应用此构造和更多的构造指令,请参考这篇文章。
Method2
这是一种很少应用的形式(应用两个<ng-template>
)。这里咱们在then中给出了一个模板援用,通知他当条件为真时候应该渲染什么。
像这样应用多<ng-template>
(你能够应用<ng-container>
代替)是不被倡议的因为这不是Angular的本意。<ng-template>
该当被应用在多处重复使用的场景下。咱们将在文章前面的局部更具体的探讨。
< ng-container >
你是否已经写过或看到过相似这样的代码
咱们大部分人写这样代码的起因在于Angular无奈再单个元素上应用多个构造指令。当初这个代码失常工作,然而如果item.id 为false,它就会在dom中引入很多空的<div>
在简略的例子中可能不须要关怀它,但如果在大型简单的利用中时候(会展现成千上万的数据),它可能变得麻烦,因为有可能会有监听器在这些DOM上。
更蹩脚的是你可能必须去嵌套你的CSS。【大略是想表白这些写会在附加款式时候须要额定的选择器】
不要放心!咱们有<ng-container>
能够解决。
<ng-container>
是一个组元素,它不会烦扰款式或布局,因为Angular不会将它们渲染到DOM中。
以上代码会渲染出这样的DOM构造
看,咱们解脱了那些空的div。咱们应该应用<ng-container>
当咱们仅仅想应用多个构造指令而不想引入多的DOM时候。
3、< ng-content >
它用于创立可配置的组件。这意味着组件能够依据用户的志愿来配置。这就是家喻户晓的内容投影~
思考一个简略的应用了<ng-content>
的组件
在<project-content>
组件的开始标记和完结标记之间是将要被内容投影的内容。【也就是vue和react的slot】
这些内容将被渲染在组件的<ng-content>
中,这将容许自定义<project-content>
组件的页脚局部。
多重投影
如果你能够决定哪些内容能够被渲染到哪些地方会怎么?您还能够应用<ng-content>
的select属性来管制内容的投影形式,而不是在单个的<ng-content>
中投影每个内容。它须要一个元素选择器来决定特定的<ng-content>
中投影哪些内容.
办法如下:
咱们批改<project-content>
来演示如何应用多内容投影。Select属性选择器将在特定的<ng-content>
中出现的内容。这里咱们首先抉择出现h1元素,如果投射的内容中没有h1元素,它将不会渲染任何内容。同样,第二个抉择查找div。其余的内容在最初一个<ng-content>
中出现。
以上的形式应该是老版本的Angular了,当初的Angular文档中没有提到,当初的应用形式请查看最新文档
4、*ngTemplateOutlet
*ngTemplateOutlet
个别被用在两个场景:
- 不管循环或条件如何,在视图中插入一个公共模板
- 创立一个高度配置的组件
模版重用
思考一个视图,其必须在多个地位插入模板。例如,要搁置在网站中的公司logo。咱们能够通过为logo编写一次模板并在视图的任何中央重用来实现它。
上面是代码片段:
正如你看到的,咱们只写了一次模板代码,并应用了它三次!
<*ngTemplateOutlet>
也承受一个上下文对象,能够传递改对象来自定义通用模板输入。无关上下文的更多信息,请参阅官网文档
自定义组件
<*ngTemplateOutlet>
的第二个应用形式是高度订制组件。思考咱们之前的<project-content>
的示例。并进行一些批改。
下面是<project-content>
组件的批改版本,它承受三个属性 —— <headerTemplate>
<bodyTemplate>
<footerTemplate>
。上面是其代码片段:
咱们在这里视图实现的是显示从<project-content>
的父组件承受到的页眉,注释和页脚。如果其中任何一个未提供,咱们的组件在其地位展现默认模版。因而,创立了一个高度订制的组件。
当初应用咱们刚创立的组件:
这是咱们如何传递一个 template refs 给咱们的组件的形式。如果其中任何一个没有传递,组件将渲染默认的模板!
ng-content vs *ngTemplateOutlet
它们都帮咱们实现了高度自定义的组件,然而咱们该如何抉择它们呢?
能够革除的看到,*ngTemplateOutlet
给了咱们更多的能力,例如提供默认的模板...
但 <ng-content>
智能依照原样出现内容,借助select属性,您能够拆分内容并在视图的不同地位出现它们。您不能有条件的出现<ng-content>
的内容。您必须限度从父组件哪里承受到的内容,而无奈依据内容做出决定。
无论如何,在这两个间进行抉择齐全取决于你的用例。至多当初咱们有了一个新的武器 *ngTemplateOutlet
,它提供了更多的控制权比照<ng-content>