
声明
本篇为 Angular 中相对高级的教程,涉及到了结构性指令、生命周期重要概
念。建议这块不熟悉的读者可以看看 Angular 结构型指令 NgIf 原理 ,这篇文
章中我结合源码对 Angular 指令中的黑魔法做了解析。
视图
Angular 中视图是一个重要的概念。从源码角度来看,Angular 中的视图是包
含页面结点(DOM)与在此之上的绑定(数据)的结构体,通过视图 Angular
将变量与页面结点进行关联,从而可以在执行变更检测等操作时实现控制层数
据与页面结点的联动,这也也是绑定 (binding)这一术语的由来。
正是因为视图是 Angular 的核心所在,在 Angular 中想要创建一个页面片段
最好的方式也是把这个页面片段当做一个视图。由内置指令 NgIf、NgFor 的实
现可知,我们可以利用模板 <ng-tempalte> 来创建这个页面片段的视图,这个
视图在 Angular 中又被称作嵌入式视图。换句话说,嵌入式视图本身就是视
图,特殊之处在它是由模板创建而来罢了。
嵌入式视图的创建方法有两种,一种办法是直接利用 Angular 内置指令。这种
方法直接在组件对应模板上就能完成嵌入式视图的创建。缺点是使用场景比较
局限,只能作用于组件模板上。另一种方法是直接在组件的控制层中利用内置
对象完成嵌入式视图的创建。这种方法相对麻烦一点,但胜在灵活,在组件和
指令中都能使用。
简单但笨重
Angular 提供了一个 ngTemplateOutlet 指令。我们只要将这个指令作用与某
个元素(一般来说是容器元素 <ng-container>),就会自动在这个元素下创建
一个嵌入式视图。

如上所示,我们可以在 NgTemplateOutlet 中 context 输入变量中指定我们的
上下文环境变量。上下文环境变量通俗的说就是一组参数。我们可以在模板中
使用 let 语法来接受上下文环境信息。
这里模板中 let-name = “localSk” 表明模板内建了一个 name 变量,用于接受
NgTemplateOutlet 传过来的上下文环境变量中 locakSk 的信息。
繁琐但灵活
采用 Angular 内置类 viewContainerRef ( 视图容器引用)与 templateRef
( 视图模板引用 )创建嵌入式视图相对比较繁琐,但是可以同时作用于组件与
指令,因此在灵活性上更胜一筹。
作用于指令时,可通过依赖注入的方式得到指令作用宿主 viewContainerRef
和 templateRef 。然后通过 viewContainerRef 的 createEmbeddedView 方
法传入 templateRef 和 上下文环境变量来创建嵌入视图。

一旦传入上下文环境变量,你就可以在 ng-tempalte 中使用 let 语法绑定这个
环境变量,并在子元素中使用它。

作用于组件时,唯一需要注意的是,调用 createEmbedded 方法的生命周期要
在 ngAfterViewInit 之后。这是因为 ViewChild 修饰符获取元素的引用,需要
在组件初始化完成后才能生效。其他的用法和做用于指令时相同。

万剑归宗
两种方式虽然形式不同,但都本着一个逻辑。即在视图容器中创建一个视图模
板,并通过某种方法将上下文参数带给后者。理解了这点就不难做到灵活使用
它们。