全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

浅谈angular4 ng-content 中隐藏的内容

如果你尝试在 Angular 中编写可重复使用的组件,则可能会接触到内容投射的概念。然后你发现了 <ng-content> ,并找到了一些关于它的文章,进而实现了所需的功能。

接下来我们来通过一个简单的示例,一步步介绍 <ng-content> 所涉及的内容。

Simple example

在本文中我们使用一个示例,来演示不同的方式实现内容投影。由于许多问题与Angular 中的组件生命周期相关,因此我们的主要组件将显示一个计数器,用于展示它已被实例化的次数:

import { Component } from '@angular/core';

let instances = 0;

@Component({
 selector: 'counter',
 template: '<h1>{{this.id}}</h1>'
})
class Counter {
 id: number;
 
 constructor() {
  this.id = ++instances;
 }
}

上面示例中我们定义了 Counter 组件,组件类中的 id 属性用于显示本组件被实例化的次数。接着我们继续定义一个 Wrapper 组件:

import { Component } from '@angular/core';

@Component({
 selector: 'wrapper',
 template: `
  <div class="box">
   <ng-content></ng-content>
  </div>
 `
})
class Wrapper {}

现在我们来验证一下效果:

<wrapper>
 <counter></counter>
 <counter></counter>
 <counter></counter>
</wrapper>

Targeted projection

有时你希望将包装器的不同子项投影到模板的不同部分。为了处理这个问题, <ng-content> 支持一个 select 属性,可以让你在特定的地方投射具体的内容。该属性支持 CSS 选择器(my-element,.my-class,[my-attribute],...)来匹配你想要的内容。如果 ng-content 上没有设置 select 属性,它将接收全部内容,或接收不匹配任何其他 ng-content 元素的内容。长话短说:

import { Component } from '@angular/core';

@Component({
 selector: 'wrapper',
 template: `
 <div class="box red">
  <ng-content></ng-content>
 </div>
 <div class="box blue">
  <ng-content select="counter"></ng-content>
 </div>
 `,
 styles: [`
  .red {background: red;}
  .blue {background: blue;}
 `]
})
export class Wrapper { }

上面示例中,我们引入了 select 属性,来选择投射的内容:

<wrapper>
 <span>This is not a counter</span>
 <counter></counter>
</wrapper>

上述代码成功运行后,counter 组件被正确投影到第二个蓝色框中,而 span 元素最终会在全部红色框中。请注意,目标 ng-content 会优先于 catch-all,即使它在模板中的位置靠后。

ngProjectAs

有时你的内部组件会被隐藏在另一个更大的组件中。有时你只需要将其包装在额外的容器中即可应用 ngIf ngSwitch。无论什么原因,通常情况下,你的内部组件不是包装器的直接子节点。为了演示上述情况,我们将 Counter 组件包装在一个 <ng-container> 中,看看我们的目标投影会发生什么:

<wrapper>
 <ng-container>
  <counter></counter>
 </ng-container>
</wrapper>

现在我们的 couter 组件会被投影到第一个红色框中。因为 ng-container 容器不再匹配 select="counter"。为了解决这个问题,我们必须使用 ngProjectAs 属性,它可以应用于任何元素上。具体如下:

<wrapper>
 <ng-container ngProjectAs="counter">
  <counter></counter>
 </ng-container>
</wrapper>

通过设置 ngProjectAs 属性,终于让我们的 counter 组件重回蓝色框的怀抱了。

Time to poke and prod

我们从一个简单的实验开始:将两个 <ng-content> 块放在我们的模板中,没有选择器。会出现什么情况?

页面中会显示一个或两个框,如果我们包含两个框,它们的内容是显示 1 和 1 或 1 和 2?

<div class="box red">
  <ng-content></ng-content>
</div>
<div class="box blue">
  <ng-content></ng-content>
</div>

答案是我们在最后一个 <ng-content> 中得到一个计数器,另一个是空的!在我们尝试解释为什么之前,让我们再来验证一个问题,即在 ng-content 指令的外层容器中添加 ngIf 指令:

import { Component } from '@angular/core';

@Component({
 selector: 'wrapper',
 template: `
  <button (click)="show = !show">
   {{ show ? 'Hide' : 'Show' }}
  </button>
  <div class="box" *ngIf="show">
   <ng-content></ng-content>
  </div>
 `
})
class Wrapper {
 show = true;
}

乍一看,似乎正常运行。但是如果你通过按钮进行切换操作,你会注意到计数器的值不会增加。这意味着我们的计数器组件只被实例化了一次 - 从未被销毁和重新创建。难道这是 ngIf 指令产生的问题,让我们测试一下 ngFor 指令,看看是否有同样的问题:

import { Component } from '@angular/core';

@Component({
 selector: 'wrapper',
 template: `
  <div class="box" *ngFor="let item of items">
   <ng-content></ng-content>
  </div>
 `
})
class Wrapper {
 items = [0, 0, 0];
}

以上代码运行后与我们使用多个 <ng-content> 的效果是一样的,只会显示一个计数器!为什么不按照我们的预期运行?

The explanation

<ng-content> 不会 "产生" 内容,它只是投影现有的内容。你可以认为它等价于 node.appendChild(el) 或 jQuery 中的 $(node).append(el) 方法:使用这些方法,节点不被克隆,它被简单地移动到它的新位置。因此,投影内容的生命周期将被绑定到它被声明的地方,而不是显示在地方。

这种行为有两个原因:期望一致性和性能。什么 "期望的一致性" 意味着作为开发人员,可以基于应用程序的代码,猜测其行为。假设我写了以下代码:

<div class="my-wrapper">
 <counter></counter>
</div>

很显然计数器将被实例化一次,但现在假如我们使用第三方库的组件:

<third-party-wrapper>
 <counter></counter>
</third-party-wrapper>

如果第三方库能够控制 counter 组件的生命周期,我将无法知道它被实例化了多少次。其中唯一方法就是查看第三方库的代码,了解它们的内部处理逻辑。将组件的生命周期被绑定到我们的应用程序组件而不是包装器的意义是,开发者可以掌控计数器只被实例化一次,而不用了解第三方库的内部代码。

性能的原因更为重要。因为 ng-content 只是移动元素,所以可以在编译时完成,而不是在运行时,这大大减少了实际应用程序的工作量。

The solution

为了让包装器能够控制其子元素的实例化,我们可以通过两种方式完成:在我们的内容周围使用 <ng-template> 元素,或者使用带有 "*" 语法的结构指令。为简单起见,我们将在示例中使用 <ng-template> 语法,我们的新应用程序如下所示:

<wrapper>
 <ng-template>
  <counter></counter>
 </ng-template>
</wrapper>

包装器不再使用 <ng-content>,因为它接收到一个模板。我们需要使用 @ContentChild 访问模板,并使用ngTemplateOutlet 来显示它:

@Component({
 selector: 'wrapper',
 template: `
  <button (click)="show = !show">
   {{ show ? 'Hide' : 'Show' }}
  </button>
  <div class="box" *ngIf="show">
   <ng-container [ngTemplateOutlet]="template"></ng-container>
  </div>
 `
})
class Wrapper {
 show = true;
 @ContentChild(TemplateRef) template: TemplateRef;
}

现在我们的 counter 组件,每当我们隐藏并重新显示时都正确递增!让我们再验证一下 *ngFor 指令:

@Component({
 selector: 'wrapper',
 template: `
  <div class="box" *ngFor="let item of items">
   <ng-container [ngTemplateOutlet]="template"></ng-container>
  </div>
 `
})
class Wrapper {
 items = [0, 0, 0];
 @ContentChild(TemplateRef) template: TemplateRef;
}

上面代码成功运行后,每个盒子中有一个计数器,显示 1,2 和 3,这正是我们之前预期的结果。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# angular4  # ng  # content隐藏内容  # content  # 浅谈Angular2 ng-content 指令在组件中嵌入内容  # 如何用DevUI搭建自己的Angular组件库  # 详解Angular数据绑定及其实现方式  # 详解React Angular Vue三大前端技术  # Angular性能优化之第三方组件和懒加载技术  # Angular框架详解之视图抽象定义  # AngularJS 中括号的作用详解  # 详解Angular组件之投影  # 让我们  # 第三方  # 应用程序  # 如果你  # 框中  # 将被  # 绑定  # 到第  # 装在  # 而不是  # 这是  # 是在  # 选择器  # 让你  # 你可以  # 多个  # 在我们的  # 你会  # 将在  # 两种 


相关文章: 如何选择可靠的免备案建站服务器?  mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?  无锡营销型网站制作公司,无锡网选车牌流程?  简单实现Android验证码  建站之星后台管理:高效配置与模板优化提升用户体验  清除minerd进程的简单方法  详解jQuery中基本的动画方法  微信小程序制作网站有哪些,微信小程序需要做网站吗?  如何正确选择百度移动适配建站域名?  c# 在高并发下使用反射发射(Reflection.Emit)的性能  如何快速生成可下载的建站源码工具?  html制作网站的步骤有哪些,iapp如何添加网页?  西安专业网站制作公司有哪些,陕西省建行官方网站?  MySQL查询结果复制到新表的方法(更新、插入)  建站主机助手选型指南:2025年热门推荐与高效部署技巧  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  建站之星微信建站一键生成小程序+多端营销系统  制作网站公司那家好,网络公司是做什么的?  网站制作报价单模板图片,小松挖机官方网站报价?  定制建站是什么?如何实现个性化需求?  如何快速生成高效建站系统源代码?  音乐网站服务器如何优化API响应速度?  C#怎么使用委托和事件 C# delegate与event编程方法  长沙做网站要多少钱,长沙国安网络怎么样?  天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?  建站ABC备案流程中有哪些关键注意事项?  微信推文制作网站有哪些,怎么做微信推文,急?  新网站制作渠道有哪些,跪求一个无线渠道比较强的小说网站,我要发表小说?  ui设计制作网站有哪些,手机UI设计网址吗?  如何制作算命网站,怎么注册算命网站?  独立制作一个网站多少钱,建立网站需要花多少钱?  网站制作软件免费下载安装,有哪些免费下载的软件网站?  企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?  建站主机如何选?性能与价格怎样平衡?  在线教育网站制作平台,山西立德教育官网?  制作网站的过程怎么写,用凡科建站如何制作自己的网站?  Android自定义listview布局实现上拉加载下拉刷新功能  用v-html解决Vue.js渲染中html标签不被解析的问题  如何通过可视化优化提升建站效果?  北京制作网站的公司,北京铁路集团官方网站?  免费网站制作模板下载,除了易企秀之外还有什么H5平台可以制作H5长页面,最好是免费的?  南平网站制作公司,2025年南平市事业单位报名时间?  官网建站费用明细查询_企业建站套餐价格及收费标准指南  网站建设设计制作营销公司南阳,如何策划设计和建设网站?  如何用西部建站助手快速创建专业网站?  如何在腾讯云服务器上快速搭建个人网站?  如何在云主机上快速搭建多站点网站?  开源网站制作软件,开源网站什么意思?  如何通过西部数码建站助手快速创建专业网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。