Angular 在哪里为 *ngIf 定义了“作为 local-var”行为?

Posted

技术标签:

【中文标题】Angular 在哪里为 *ngIf 定义了“作为 local-var”行为?【英文标题】:Where does Angular define "as local-var" behavior for *ngIf? 【发布时间】:2018-03-18 21:15:11 【问题描述】:

我试图了解 ngIf 的“as local-var”可选行为在哪里定义,例如: *ngIf="user$ | async as user"

尝试查看源代码中的明显位置,例如 https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts

但代码中没有任何内容,只有文档。

有谁知道这个魔法发生在代码的什么地方?

【问题讨论】:

这可能在异步管道内吗? Nope :) 也检查了它。 我认为它应该在解析器中的某个地方,因为我们可以对它不真正属于 ngIf 的任何值指令执行操作 肯定会在compiler 模块中的某个地方? 【参考方案1】:

是的,这是在模板编译期间发生的魔法。

下面的模板

<div *ngIf="user$ | async as user"></div>

只是糖:

<ng-template [ngIf]="user$ | async" let-user="ngIf">
  <div></div>
</ng-template>

所以答案是:下面的字符串将值传递给这个变量:

this._context.$implicit = this._context.ngIf = condition;
                                ^^^^^^^^^^^^^

https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts#L115

例如我们可以创建结构指令ngVar:

@Directive(
  selector: '[ngVar]',
)
export class VarDirective 
  @Input()
  set ngVar(context: any) 
    this.context.$implicit = this.context.ngVar = context;
                              ^^^^^^^^^^^^^^^^
    this.updateView();
  

  context: any = ;

  constructor(private vcRef: ViewContainerRef, private templateRef: TemplateRef<any>) 

  updateView() 
    this.vcRef.clear();
    this.vcRef.createEmbeddedView(this.templateRef, this.context);
  

并像这样使用它:

<ng-template [ngVar]="true" let-x="ngVar"><div>x</div></ng-template>

<div *ngVar="true as x">x</div>

有什么魔力?

如果您想了解编译器的魔力在哪里,那么让我们看一个示例:

<div *ngVar="true as x"></div>

1) Angular 编译器将这个字符串标记为:

<div *ngVar="true as x"></div>
 (1)   (2)      (3)   (4) (5)


(1) - TAG_OPEN_START
(2) - ATTR_NAME
(3) - ATTR_VALUE
(4) - TAG_OPEN_END
(5) - TAG_CLOSE

2) htmlParser 基于这些标记创建元素树:

Element div
       attrs: name:  *ngIf
              value: true as x

3) TemplateParser 构建 AST(抽象语法节点)树。为此,TemplateParser 使用名为 TemplateParseVisitor 的特殊访问者

此访问者浏览上一步中收到的所有树。并且让我们看看编译器来到visitElement时它是如何工作的:

所以我们可以看到任何带有结构指令的模板,例如:

*dir="someValue as someVar"

代表以下内容:

<ng-template [dir]="someValue" let-someVar="dir">

另见:

https://alexzuza.github.io/enjoy-ng-parser/ Angular2: How is ngfor expanded How to declare a variable in a template in Angular2

【讨论】:

哇......所以它实际上是“让任何东西”指令? local var 的名称在哪里? 看来您的帖子还没有完成 :) 请继续。 (我在词法分析器中找到了“as”关键字,但无法连接关于“this.context.$implicit”实际上如何将变量放入范围......因为这是范围? 没有“let-ANYTHING”指令。编译器只是根据结构语法在内部创建变量 let-anything 这样*dir="someValue as someVar" 将是&lt;ng-template [dir]="someValue" let-someVar="dir"&gt; 这太棒了。但我就是不明白为什么它还没有在框架中。而且我必须相信它不存在是有原因的——比如它可能不适用于变更检测或其他类似的奇怪现象。需要这样的功能是否意味着我们在使用模板时做错了什么?还是我们都应该使用它?

以上是关于Angular 在哪里为 *ngIf 定义了“作为 local-var”行为?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 5 自定义指令触发包装到 *ngIf=false 中的元素

无法读取未定义 angular2 ngif 的属性

angular入门篇(2)——*ngIf,数据绑定事件,属性绑定

如果模板包含 *ngIf,Angular 自定义结构指令无法重建 ViewContainer

Angular 2+ - 当 ngIf 导致隐藏时将 ngModel 设置为 null

ngIf 未定义的 HTML 检查变量不包括值为 0 时的情况