Angular2:ngfor如何扩展 [英] Angular2: How is ngfor expanded

查看:63
本文介绍了Angular2:ngfor如何扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know the textbook rules on that <div *ngFor="let foo of foobars">{{foo.stuff}}</div> turns into <template ngFor let-foo="$implicit" [ngForOf]="foobars"><div>...</div></template>. My question is two-fold:

  • 如何?
  • 我需要做什么以自己利用这种机制(微语法")?

<div *myDirective="item">{{item.stuff}}</div>转换为<template myDirective let-item="$implicit"><div>{{item.stuff}}</div></template>吗?

由于我是从上至下阅读ngFor的源代码的,所以我只能假定这种黑魔法存在于编译器中的某个位置,我一直在有角度的github上下滑动,但我无法动弹. 帮助!

Since I read ngFor's source code top to bottom, I can only assume this dark magic is in the compiler somewhere, I've been up and down the angular github, but I can't put my finger on it. Help!

推荐答案

是的,所有魔术都发生在编译器中.

Yes, all magic happens in the compiler.

让我们使用此模板:

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

首先将其转换为以下内容:

First it will be transformed to the following:

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

然后:

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

在Angular2 rc.4中,它看起来像这样

In Angular2 rc.4 it looks like this

首先生成一个ast树节点(抽象语法树节点),然后所有魔术都发生在TemplateParseVisitor.visitElement(

First is generated ast tree node (Abstract Syntax Tree node) and then all magic happens in the TemplateParseVisitor.visitElement(https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L284) specifically at the bottom (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>

进入

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

然后您需要使用以下语法:

then you need to use the following syntax:

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

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

But in this case you won't pass context. Your custom structural directive might look like this:

@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>

我希望这可以帮助您了解结构性指令的工作方式.

I hope this will help you understand how structural directives work.

更新:

让我们看看它是如何工作的( plunker )

Let's see how it works (plunker)

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

因此您可以编写以下指令:

So you can write the following directive:

@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]
}

这是对应的 柱塞

Here is the corresponding Plunker

另请参见

  • 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://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://alexzuza.github.io/enjoy-ng -parser/

Live example you can find here https://alexzuza.github.io/enjoy-ng-parser/

这篇关于Angular2:ngfor如何扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆