Heim  >  Artikel  >  Web-Frontend  >  Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

青灯夜游
青灯夜游nach vorne
2021-07-14 10:40:312115Durchsuche

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

Ich bin jemand, der Artikel schreibt oder über seine Erfahrungen spricht. Ich kopiere nicht gerne Dinge direkt von der offiziellen Website. Ich schreibe immer noch gerne Artikel in meiner Landessprache. Ich habe heute lange auf der offiziellen Website über Vorlageneingabevariablen gelesen und endlich eine vorläufige Vorstellung davon bekommen, was das ist. [Verwandte Tutorial-Empfehlung: „Angular-Tutorial“]

Was genau sind Vorlageneingabevariablen

Der Grund, warum ich dieses Ding studieren möchte, ist, dass ich bei der Verwendung von ng-zorro zuvor dessen Paging verwendet habe Komponente PaginierungOffizieller Website-LinkPagination官网链接)。这其中有一个自定义上一页下一页模板的功能。代码的话如下:

@Component({
  selector: 'nz-demo-pagination-item-render',
  template: `
    <nz-pagination [nzPageIndex]="1" [nzTotal]="500" [nzItemRender]="renderItemTemplate"></nz-pagination>
    <ng-template #renderItemTemplate let-type let-page="page">
      <ng-container [ngSwitch]="type">
        <a *ngSwitchCase="&#39;page&#39;">{{ page }}</a>
        <a *ngSwitchCase="&#39;prev&#39;">Previous</a>
        <a *ngSwitchCase="&#39;next&#39;">Next</a>
        <a *ngSwitchCase="&#39;prev_5&#39;"><<</a>
        <a *ngSwitchCase="&#39;next_5&#39;">>></a>
      </ng-container>
    </ng-template>
  `
})
export class NzDemoPaginationItemRenderComponent {}

看完这个之后我就很是疑惑,这个let是啥,为啥let-跟上一个变量之后就有值了呢?然后我就开始在官网中找这个let是什么东西。最终,我在主要概念-指令-结构性指令微语法一节找到了关于let的说明。官网描述:微语法

在下面还有一段简短的说明:

模板输入变量(Template input variable)

模板输入变量是这样一种变量,你可以在单个实例的模板中引用它的值。 这个例子中有好几个模板输入变量:heroiodd。 它们都是用 let 作为前导关键字。

......

你使用 let 关键字(如 let hero)在模板中声明一个模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。 事实上,你可以在其它结构型指令中使用同样的变量名。

......

官网还是一如既往的不说人话,短短几句话就给你介绍完了,也不告诉你这玩意怎么用,也不告诉你let声明的变量的值到底是从哪里来的。我越看越气,得,官网你不说,我自己找。

先说一个粗略的结论:let声明的变量是这个template模板的上下文对象中的变量。不然为啥叫模板输入变量呢。在*ngFor内幕这小节中,我们了解到了其内幕,结构性指令其实就是将宿主元素包裹在一个<ng-template></ng-template>中,然后在这个模板上将*ngFor中的表达式解析成一个个的let模板输入变量和这个指令需要传入的值。由于模板中代码并不会直接被渲染成视图,所以一定需要某种方法来使模板变成视图。我们的结构性指令就是干这个事的,就是将我们的模板变成视图。

*ngFor的官方示例代码如下:

//解析前的模板
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
  ({{i}}) {{hero.name}}
</div>
//angular解析后的模板
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
  <div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
  • 在此提示一下,所谓的宿主元素就是指令所在的那个元素,像上面的例子中,div就是*ngFor指令的宿主元素。
  • trackBy这个类似于vue和react中的key。可以给模板一个标识,使其重新渲染的时候性能开销降低一些。

然后我们再看官网说的:

  • let-ilet-odd 变量是通过 let i=indexlet odd=odd 来定义的。 Angular 把它们设置为上下文对象中的 indexodd 属性的当前值。
  • 这里并没有指定 let-hero 的上下文属性。它的来源是隐式的。 Angular 将 let-hero 设置为此上下文中 $implicit 属性的值, 它是由 NgFor 用当前迭代中的英雄初始化的。

看完这段描述,我们可以得知:angular为这个模板设置了上下文对象。但是我们看不到这个过程,因为这是在ngFor的源码内部实现的。并且这个上下文对象具备indexodd属性,并且包含一个$implicit). Es gibt eine Funktion zum Anpassen der Vorlage für die vorherige Seite und die nächste Seite. Der Code lautet wie folgt:

{
    $implicit:null,
    index:null,
    odd:null,
}
🎜Nachdem ich das gelesen hatte, war ich sehr verwirrt, was ist das für ein let und warum hat let- einen Wert, nachdem ihm eine Variable folgt? Dann fing ich an, auf der offiziellen Website nach diesem let zu suchen. Schließlich habe ich die Erklärung zu let im Abschnitt „Mikrogrammatik“ von „Hauptkonzepte – Anweisungen – Strukturanweisungen“ gefunden. Offizielle Website-Beschreibung: Mikrosyntax 🎜. 🎜🎜Es gibt unten auch eine kurze Erklärung: 🎜
🎜Vorlageneingabevariable 🎜🎜Eine Vorlageneingabevariable ist eine Variable, in der Sie in einer einzelnen Instanz auf ihren Wert verweisen können em>die Vorlage. In diesem Beispiel gibt es mehrere Vorlageneingabevariablen: hero, i und odd. Sie alle verwenden let als führendes Schlüsselwort. 🎜🎜......🎜🎜Sie deklarieren eine Vorlagenvariable input in einer Vorlage mit dem Schlüsselwort let (z. B. let hero). . Der Geltungsbereich dieser Variablen ist auf die einzelne Instanz der wiederholten Vorlage beschränkt. Tatsächlich können Sie denselben Variablennamen in anderen Strukturanweisungen verwenden. 🎜🎜...🎜
🎜Die offizielle Website ist immer noch so nonverbal wie eh und je. Sie erklärt Ihnen nicht, wie Sie dieses Ding verwenden, und sagt es auch nicht Sie Woher kommt der Wert der mit let deklarierten Variablen? Je mehr ich las, desto wütender wurde ich. Wenn Sie mir nichts über die offizielle Website erzählen, werde ich sie selbst finden. 🎜🎜Beginnen wir mit einer groben Schlussfolgerung: Die von 🎜let deklarierten Variablen sind Variablen im Kontextobjekt dieser Vorlagenvorlage🎜. Warum heißt es sonst „Vorlageneingabevariable“? Im Abschnitt *🎜ngFor Insider🎜 haben wir die Insider-Geschichte erfahren. Die Strukturanweisung verpackt das Host-Element tatsächlich in ein <ng-template></ng-template> und dann darauf Vorlage wird der Ausdruck in *ngFor in jede Eingabevariable der let-Vorlage und den Wert geparst, der für diese Direktive übergeben werden muss. Da der Code in der Vorlage nicht direkt in eine Ansicht gerendert wird, muss es eine Möglichkeit geben, die Vorlage in eine Ansicht umzuwandeln. Unsere Strukturanweisungen tun genau das, indem sie unsere Vorlagen in Ansichten umwandeln. Der offizielle Beispielcode von 🎜🎜*ngFor lautet wie folgt: 🎜
@Directive({
  selector: &#39;[appRepeat]&#39;,
})
export class RepeatDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
  ) { }

  @Input() set appRepeatOf(heroesList: string[]) {
    heroesList.forEach((item, index, arr) => {
      this.viewContainer.createEmbeddedView(this.templateRef, {
        //当前条目的默认值
        $implicit: item,
        //可迭代对象的总数
        count: arr.length,
        //当前条目的索引值
        index: index,
        //如果当前条目在可迭代对象中的索引号为偶数则为 true。
        even: index % 2 === 0,
        //如果当前条目在可迭代对象中的索引号为奇数则为 true。
        odd: index % 2 === 1,
      });
    });
  }
}
  • Zur Erinnerung: Das sogenannte 🎜Host-Element🎜 ist das Element, in dem sich die Anweisung befindet, z Im obigen Beispiel ist div das Hostelement der *ngFor-Direktive.
  • trackByDies ähnelt dem Schlüssel in Vue und React. Sie können der Vorlage eine Kennung zuweisen, um den Leistungsaufwand beim erneuten Rendern zu reduzieren.
🎜Dann schauen wir uns an, was auf der offiziellen Website steht: 🎜
  • let-i und let-odd Variablen werden durch let i=index und let odd=odd definiert. Angular setzt sie auf die aktuellen Werte der Eigenschaften index und odd im Objekt Context.
  • Das Kontextattribut von let-hero wird hier nicht angegeben. Sein Ursprung ist implizit. Angular setzt let-hero in diesem Kontext auf den Wert der Eigenschaft $implicit, die von NgFor mit dem Helden in der aktuellen Iteration initialisiert wird .
🎜Nachdem wir diese Beschreibung gelesen haben, können wir wissen: 🎜Angular legt das Kontextobjekt🎜 für diese Vorlage fest. Wir können diesen Prozess jedoch nicht sehen, da er im Quellcode von ngFor implementiert ist. Und dieses 🎜Kontextobjekt🎜 hat die Attribute index und odd und enthält eine Eigenschaft $implicit (implizit: implizit; nicht direkt angegeben). Dann schließen wir, dass dieses 🎜Kontextobjekt🎜 mindestens die folgenden Attribute hat: 🎜
{
    $implicit:null,
    index:null,
    odd:null,
}

那么我们声明let变量的本质其实就是声明一个变量获取上下文对象中的同名属性的值let-hero不进行任何赋值的话,hero默认等于$implicit的值。无论是有多少个let-alet-blet-c还是let-me。声明的这个变量的值都等于$implicit的值。而我们进行赋值过的,比如let-i = "index"i的值就等于这个上下文对象中的index属性对应的值。

上下文对象是如何设置的

当我们知道这个上下文对象是什么了,就该想这个上下文对象是怎么设置的了

结构性指令这一节当中,我们跟着官方示例做了一遍这个自定义结构性指令(如果还没有做的话,建议先跟着做一遍)。在UnlessDirective这个指令中,其构造器constructor声明了两个可注入的变量,分别是TemplateRefViewContainerRef。官网给的解释我觉得太过晦涩难懂,我这里给出一下我自己的理解:TemplateRef代表的是宿主元素被包裹之后形成的模板的引用。而ViewContainerRef代表的是一个视图容器的引用。那么问题来了,这个视图容器在哪儿呢?我们在constructor构造器中打印一下ViewContainerRef。打印结果如图:

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

然后我们点进去这个comment元素。发现其就是一个注释元素。如图所示:

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

其实我也不是很确定这个视图容器到底是不是这个注释元素。但是毋庸置疑的是,视图容器和宿主元素是兄弟关系,紧挨着宿主元素。我们可以使用ViewContainerRef中的createEmbeddedView() 方法(Embedded:嵌入式,内嵌式),将templateRef模板引用传入进去,创建出来一个真实的视图。由于这个视图是被插入到视图容器ViewContainerRef中了,所以又叫内嵌视图。那么这又和我们的上下文对象有什么关系呢?其实createEmbeddedView这个方法不止一个参数,其第二个参数就是给我们的模板设置上下文对象的。API的详情介绍请看createEmbeddedView这个API的详情

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用let声明变量的方法来使用这个上下文对象了。

自定义一个简单的类*ngFor指令——appRepeat

那么我们知道是如何设置的了,那么我们就来验证一下是否是对的。接下来,我们仿照ngfor的功能,自己写一个简单的渲染指令。

首先我们定义一个指令:RepeatDirective。代码如下:

@Directive({
  selector: &#39;[appRepeat]&#39;,
})
export class RepeatDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
  ) { }

  @Input() set appRepeatOf(heroesList: string[]) {
    heroesList.forEach((item, index, arr) => {
      this.viewContainer.createEmbeddedView(this.templateRef, {
        //当前条目的默认值
        $implicit: item,
        //可迭代对象的总数
        count: arr.length,
        //当前条目的索引值
        index: index,
        //如果当前条目在可迭代对象中的索引号为偶数则为 true。
        even: index % 2 === 0,
        //如果当前条目在可迭代对象中的索引号为奇数则为 true。
        odd: index % 2 === 1,
      });
    });
  }
}

然后我们将其导入NgModule中,这个过程就省略不写了。然后我们在组件中使用一下这个指令:

@Component({
  selector: &#39;app-structural-likeNgFor-demo&#39;,
  template: `
    <h2>原神1.5版本卡池角色</h2>
    <h4>自定义ngFor(appRepeat)</h4>
    <ul>
      <li *appRepeat="let h of heroesList;let i = index;let even = even">
        索引:{{i}} -- {{h}} -- 索引值是否是偶数:{{even.toString()}}
      </li>
    </ul>
    <h4>真正的ngFor</h4>
    <ul>
      <li *ngFor="let h of heroesList;let i = index;let even = even">
        索引:{{i}} -- {{h}} -- 索引值是否是偶数:{{even.toString()}}
      </li>
    </ul>
  `,
})
export class StructuralLikeNgForDemoComponent {
  public heroesList: string[] = [&#39;钟离&#39;, &#39;烟绯&#39;, &#39;诺艾尔&#39;, &#39;迪奥娜&#39;];
}

在这里需要注意的是指令中的appRepeatOf不是乱写的。在微语法的解析过程中let h of heroesList中的of首先首字母会变成大写的,变成Of。然后在给它加上这个指令的前缀,也就是appRepeat。组合起来就是appRepeatOf了。由它来接收一个可迭代的对象。

最后显示的效果图:

Lassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen

运行结果的话和*ngFor没有区别。但是功能肯定是欠缺的,如果有能力的小伙伴可以去阅读*ngFor的源码:*ngFor的源码

Zusammenfassung

Durch diesen Artikel wissen wir, dass die let-variable let-变量这个模板输入变量是通过模板的上下文对象中定义并获取值的。然后想要设置上下文对象的话需要通过createEmbeddedView方法的第二个参数来设置。

结语

但是我总觉得了解的还不够透彻,我总觉得设置模板的上下文对象可能不只是createEmbeddedViewVorlageneingabevariable

definiert ist und den Wert über das
Kontextobjekt

der Vorlage erhält. Wenn Sie dann das Kontextobjekt festlegen möchten, müssen Sie es über den zweiten Parameter der Methode createEmbeddedView festlegen.

Fazit

Aber ich habe immer das Gefühl, dass das Verständnis nicht gründlich genug ist. Ich habe immer das Gefühl, dass das

Kontext

-Objekt, das die Vorlage festlegt, möglicherweise nicht nur ist createEmbeddedView Eine Möglichkeit, aber ich habe keine andere Möglichkeit gefunden. Wenn ihr andere Methoden kennt, hinterlasst bitte eine Nachricht und lasst es mich wissen. 🔜 :
Einführung in die Programmierung

! !

Das obige ist der detaillierte Inhalt vonLassen Sie uns über Vorlageneingabevariablen (Let-Variablen) in Angular sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen