ng-content、ng-template、ng-container使用及区别

257 阅读5分钟

三者使用场景说明
ng-container常用来循环元素
ng-content常在组件封装的使用使用
ng-template配合ngIf使用

一、ng-content

1.1基础组件及结构

app.component.ts
father-component.ts

image.png

father-component.html

image.png

father-component.css

image.png

此时我们引用该组件,就会呈现该组件解析之后的内容:

<app-father-component></app-father-component>

image.png

如果说这个组件能够接受外部投射进来的内容,也就是说组件最终呈现的内容不仅仅是本身定义的那些,那该怎么做呢?这时就要请出本文的主角 ng-content。

1.2简单投射

先修改father-component.html和father-component.css

father-component.html:

image.png

father-component.css:

image.png

为了效果展示特意将 所在的容器背景色定义为橙色。
这时我们在引用该组件时可以从外部投射内容,外部内容将在橙色区域显示:

<app-father-component>
    外部嵌入的内容
</app-father-component>

image.png

1.3 针对性性投射

如果同时存在几个 ,那外部内容将如何进行投射呢?
我们先看个示例,为了区别,我再新增一个蓝色区域的 ,修改后的father-component.html和 father-component.css 如下:

demo.component.html:

<div class="demo">
    <h2>
      一个简单的组件
    </h2>
    <div class="content">
      <ng-content></ng-content>
    </div>
    <div class="content blue">
      <ng-content></ng-content>
    </div>
</div>

father-component.css

.demo {
	padding: 10px;
	border: 2px solid red;	
}
h2 {
    margin: 0;
    color: #262626;
}
.content {
    padding: 10px;
    margin-top: 10px;
    line-height: 20px;
    color: #FFFFFF;
    background-color: #de7d28;
}
.blue {
    background-color: blue;
}

引用组件

<app-father-component>
    外部嵌入的内容
</app-father-component>

image.png

当然,如果你将橙色区域代码放在蓝色区域代码的后面,那么外部内容就会投射到橙色区域:

<div class="demo">
    <h2>
      一个简单的组件
    </h2>
    <div class="content blue">
      <ng-content ></ng-content>
    </div>
    <div class="content">
      <ng-content></ng-content>
    </div>
</div>

image.png

所以从上面的示例我们可以看出,如果同时存在简单的 ,那么外部内容将投射在组件模板最后的那个 中。

那么知道这个问题,我们可能会想,能不能将外部内容有针对性的投射相应的 中呢?答案显然是可以的。

为了处理这个问题, 支持一个 select 属性,可以让你在特定的地方投射具体的内容。该属性支持 CSS 选择器(标签选择器、类选择器、属性选择器、…)来匹配你想要的内容。如果 ng-content 上没有设置 select 属性,它将接收全部内容,或接收不匹配任何其他 ng-content 元素的内容。 修改后的father-component.html和 father-component.css 如下:

demo.component.html:

<div class="demo">
    <h2>
      一个简单的组件
    </h2>
    <div class="content">
      <ng-content></ng-content>
    </div>
    <div class="content blue">
      <ng-content select="header"></ng-content>
    </div>
    <div class="content red">
      <ng-content select=".demo1"></ng-content>
    </div>
    <div class="content green">
      <ng-content select="[name=demo2]"></ng-content>
    </div>
  
</div>

father-component.css :

.demo {
	padding: 10px;
	border: 2px solid red;	
}
h2 {
    margin: 0;
    color: #262626;
}
.content {
    padding: 10px;
    margin-top: 10px;
    line-height: 20px;
    color: #FFFFFF;
    background-color: #de7d28;
}
.blue {
    background-color: blue;
}
.red {
    background-color: red;
}
.green {
    background-color: green;
}

组件引用

<app-father-component>
   开始, 外部嵌入的内容
   <header>
       header标签,外部嵌入的内容
    </header>
    <div class="demo1">
        我是外部嵌入的内容,我所在div的class为"demo1"
    </div>
    <div name="demo2">
        我是外部嵌入的内容demo,我所在div的属性name为"demo2"
    </div>
    结束
</app-father-component>

image.png

1.4ngProjectAs 现在我们知道通过 ng-content 的 select 属性可以指定外部内容投射到指定的 中。

而要能正确的根据 select 属性投射内容,有个限制就是,只能直接子节点。 那如果不是作为直接子节点,会是什么情况呢?我们简单修改下引用 father-component 组件的代码,将 标签header 放在一个div中,修改如下: 引用app-component.html:

<app-father-component>
   开始, 外部嵌入的内容
   <div>
    <header>
        header标签,外部嵌入的内容
     </header>
   </div>
 
    <div class="demo1">
        我是外部嵌入的内容,我所在div的class为"demo1"
    </div>
    <div name="demo2">
        我是外部嵌入的内容demo,我所在div的属性name为"demo2"
    </div>
    结束
</app-father-component>

image.png

此时,我们看到 标签 header 那部分内容不再投射到蓝色区域中了,而是投射到橙色区域中了。原因就是 无法匹配到之前的 标签 header,故而将这部分内容投射到了橙色区域的 中了。

为了解决这个问题,我们必须使用 ngProjectAs 属性,它可以应用于任何元素上。具体如下:

 <app-father-component>
    开始, 外部嵌入的内容
    <div ngProjectAs="header">
        <header>
            header标签,外部嵌入的内容
         </header>
    </div>
    <div ngProjectAs=".demo1">
        <div class="demo1">
            我是外部嵌入的内容,我所在div的class为"demo1"
        </div>
    </div>
    <div ngProjectAs="[name=demo2]">
        <div name="demo2">
            我是外部嵌入的内容demo,我所在div的属性name为"demo2"
        </div>
    </div>
     结束
 </app-father-component>

image.png

二、ng-template

ng-template是Angular 结构型指令中的一种,用于定义模板渲染HTML(模板加载)。定义的模板不会直接显示出来,需要通过其他结构型指令(如 ng-if)或 template-ref 将模块内容渲染到页面中。

<!-- 通过ngIf结构型指令显示ng-template的内容 -->
<div class="lessons-list" *ngIf="condition else elseTemplate">
    判断条件为真
</div>
<ng-template #elseTemplate>
    <div>判断条件为假</div>
</ng-template>

三、ng-container

ng-container既不是一个Component,也不是一个Directive,只是单纯的一个特殊tag。ng-container可以直接包裹任何元素,包括文本,但本身不会生成元素标签,也不会影响页面样式和布局。包裹的内容,如果不通过其他指令控制,会直接渲染到页面中。

四、区别

ng-content: ng-content是内容映射指令(也叫内容嵌入),相当于vue中的slot内容分发,内容映射指的是在组件中嵌入模板代码,方便定制可复用的组件,很好地扩充组件的功能,方便代码的复用. ng-template :使用 * 语法糖的结构指令,最终都会转换为 或 模板指令,模板内的内容如果不进行处理,是不会在页面中显示的。 ng-container:是一个逻辑容器,可用于对节点进行分组,但不作为 DOM 树中的节点,它将被渲染为 HTML中的 comment 元素,它可用于避免添加额外的元素来使用结构指令。

五、学习地址

angular之ng-container 、ng-template、ng-content的使用