Angular2:ngfor是如何扩展的

2024-04-03

我知道教科书上的规定<div *ngFor="let foo of foobars">{{foo.stuff}}</div>变成<template ngFor let-foo="$implicit" [ngForOf]="foobars"><div>...</div></template>。我的问题有两个:

  • HOW?
  • 我需要做什么才能自己利用这个机制(“微语法”)?

Ie turn <div *myDirective="item">{{item.stuff}}</div> into <template myDirective let-item="$implicit"><div>{{item.stuff}}</div></template>?

自从我从头到尾阅读了 ngFor 的源代码后,我只能假设这个黑暗魔法存在于编译器的某个地方,我已经在 Angular github 上上下了一遍,但我无法将手指放在它上面。Help!


是的,所有的魔法都发生在编译器中。

让我们看一下这个模板:

<div *ngFor="let foo of foobars">{{foo}}</div>

首先它将被转换为以下形式:

<div template="ngFor let foo of foobars>{{foo}}</div>

进而:

<template ngFor let-foo [ngForOf]="foobars"><div>{{foo}}</div></template>

In Angular2 rc.4 it looks like this enter image description here

首先生成 ast 树节点(抽象语法树节点),然后所有的魔法都发生在TemplateParseVisitor.visitElement(https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L284 https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L284)特别是在底部(https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L394 https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L394)

if (hasInlineTemplates) {
  var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
  var templateDirectiveMetas = this._parseDirectives(this.selectorMatcher, templateCssSelector);
  var templateDirectiveAsts = this._createDirectiveAsts(
      true, element.name, templateDirectiveMetas, templateElementOrDirectiveProps, [],
      element.sourceSpan, []);
  var templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts(
      element.name, templateElementOrDirectiveProps, templateDirectiveAsts);
  this._assertNoComponentsNorElementBindingsOnTemplate(
      templateDirectiveAsts, templateElementProps, element.sourceSpan);
  var templateProviderContext = new ProviderElementContext(
      this.providerViewContext, parent.providerContext, parent.isTemplateElement,
      templateDirectiveAsts, [], [], element.sourceSpan);
  templateProviderContext.afterElement();

  parsedElement = new EmbeddedTemplateAst(
      [], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts,
      templateProviderContext.transformProviders,
      templateProviderContext.transformedHasViewContainer, [parsedElement], ngContentIndex,
      element.sourceSpan);
}
return parsedElement;

该方法返回EmbeddedTemplateAst。它等同于:

<template ngFor let-foo [ngForOf]="foobars"><div>{{foo}}</div></template>

如果你想转:

<div *myDirective="item">{{item.stuff}}</div>

into

<template myDirective let-item><div>{{item.stuff}}</div></template>

那么你需要使用以下语法:

<div *myDirective="let item">{{item.stuff}}</div>

但在这种情况下,您将不会传递上下文。 您的自定义结构指令可能如下所示:

@Directive({
  selector: '[myDirective]'
})
export class MyDirective {
  constructor(
    private _viewContainer: ViewContainerRef, 
    private _templateRef: TemplateRef<any>) {}

   @Input() set myDirective(prop: Object) {
    this._viewContainer.clear();
    this._viewContainer.createEmbeddedView(this._templateRef, prop); <== pass context
  }
} 

你可以这样使用它:

<div *myDirective="item">{{item.stuff}}</div>

               ||
               \/

<div template="myDirective:item">{{item.stuff}}</div>

               ||
               \/

<template [myDirective]="item">
   <div>{{item.stuff}}</div>
</template>

我希望这将帮助您了解结构指令的工作原理。

Update:

让我们看看它是如何工作的(plunker https://plnkr.co/edit/myE61PkX7UU4nAmGDQ1x?p=preview)

*dir="let foo v foobars" => [dirV]="foobars"

所以你可以编写以下指令:

@Directive({
  selector: '[dir]'
})
export class MyDirective {
  @Input()
  dirV: any;

  @Input()
  dirK: any;

  ngAfterViewInit() {
    console.log(this.dirV, this.dirK);
  }
}

@Component({
  selector: 'my-app',
  template: `<h1>Angular 2 Systemjs start</h1>
  <div *dir="let foo v foobars k arr">{ foo }</div>
  `,
  directives: [MyDirective]
})
export class AppComponent {
  foobars = [1, 2, 3];
  arr = [3,4,5]
}

这里是对应的Plunker https://plnkr.co/edit/bKbWiUYiGmNh5l3yiUhG?p=preview

See also

  • https://angular.io/docs/ts/latest/guide/structural-directives.html#!#the-asterisk-effect https://angular.io/docs/ts/latest/guide/structural-directives.html#!#the-asterisk-effect
  • https://teropa.info/blog/2016/03/06/writing-an-angular-2-template-directive.html https://teropa.info/blog/2016/03/06/writing-an-angular-2-template-directive.html
  • https://www.bennadel.com/blog/3076-creating-an-index-loop-structural-directive-in-angular-2-beta-14.htm https://www.bennadel.com/blog/3076-creating-an-index-loop-structural-directive-in-angular-2-beta-14.htm
  • https://egghead.io/lessons/angular-2-write-a-structural-directive-in-angular-2 https://egghead.io/lessons/angular-2-write-a-structural-directive-in-angular-2

您可以在这里找到实例https://alexzuza.github.io/enjoy-ng-parser/ https://alexzuza.github.io/enjoy-ng-parser/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular2:ngfor是如何扩展的 的相关文章

随机推荐