Angular开发实践(八):使用ng-content进行组件内容投射

在Angular中,组件属于特殊的指令,它的特殊之处在于它有自己的模板(html)和样式(css)。因此使用组件可以使我们的代码具有强解耦、可复用、易扩展等特性。通常的组件定义如下:

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

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

简单投射

为了效果展示特意将所在的容器背景色定义为橙色。

这时我们在引用该组件时可以从外部投射内容,外部内容将在橙色区域显示:

针对性投射

如果同时存在几个,那外部内容将如何进行投射呢?

引用该组件:

此时,我们将看到外部内容投射到了蓝色区域:

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

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

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

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

从上面代码可以看到,蓝色区域将接收 那部分内容,红色区域将接收 的那部分内容,绿色区域将接收 的那部分内容,橙色区域将接收其余的外部内容()。

引用该组件:

此时,我们将看到外部内容投射到了指定的中。

扩展知识

ngProjectAs

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

而要能正确的根据 属性投射内容,有个限制就是- 不管是 、还是 ,这几个标签都是作为 组件标签的。

那如果不是作为直接子节点,会是什么情况呢?我们简单修改下引用 demo-component 组件的代码,将 放在一个div中,修改如下:

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

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

通过设置 属性,让 所在的 div 指向了 ,此时 那部分内容有投射到蓝色区域了:

不“产生”内容做个试验

做个试验,先定义一个 demo-child-component 组件:

demo-component 组件修改为:

然后在 demo-component 中 投射 demo-child-component:

此时,在控制台我们看到打印出 这些文字。但是当我们点击按钮进行切换操作时, 就不再打印了,这意味着我们的 demo-child-component 组件只被实例化了一次 - 从未被销毁和重新创建。

为什么会出现这样的情况呢?

出现原因

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

这也从原理解释了前面那个问题:如果同时存在几个,那外部内容将如何进行投射呢?

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

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

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

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

解决方法

为了让组件能够控制投射进来的子组件的实例化,我们可以通过两种方式完成:在我们的内容周围使用 元素及 ngTemplateOutlet,或者使用带有 "*" 语法的结构指令。为简单起见,我们将在示例中使用 语法。

demo-component 组件修改为:

然后我们将 demo-child-component 包含在 中:

此时,我们在点击按钮进行切换操作时,控制台都会打印出 这些文字。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180405G0ST8M00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券