Heim > Artikel > Web-Frontend > 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“]
Der Grund, warum ich dieses Ding studieren möchte, ist, dass ich bei der Verwendung von ng-zorro zuvor dessen Paging verwendet habe Komponente Paginierung
(Offizieller 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="'page'">{{ page }}</a> <a *ngSwitchCase="'prev'">Previous</a> <a *ngSwitchCase="'next'">Next</a> <a *ngSwitchCase="'prev_5'"><<</a> <a *ngSwitchCase="'next_5'">>></a> </ng-container> </ng-template> ` }) export class NzDemoPaginationItemRenderComponent {}
看完这个之后我就很是疑惑,这个let是啥,为啥let-
跟上一个变量之后就有值了呢?然后我就开始在官网中找这个let
是什么东西。最终,我在主要概念-指令-结构性指令的微语法一节找到了关于let
的说明。官网描述:微语法。
在下面还有一段简短的说明:
模板输入变量(Template input variable)
模板输入变量是这样一种变量,你可以在单个实例的模板中引用它的值。 这个例子中有好几个模板输入变量:
hero
、i
和odd
。 它们都是用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-i
和let-odd
变量是通过let i=index
和let odd=odd
来定义的。 Angular 把它们设置为上下文对象中的index
和odd
属性的当前值。- 这里并没有指定
let-hero
的上下文属性。它的来源是隐式的。 Angular 将let-hero
设置为此上下文中$implicit
属性的值, 它是由NgFor
用当前迭代中的英雄初始化的。
看完这段描述,我们可以得知:angular为这个模板设置了上下文对象。但是我们看不到这个过程,因为这是在ngFor
的源码内部实现的。并且这个上下文对象具备index
和odd
属性,并且包含一个$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:🎜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 Siehero
,i
undodd
. Sie alle verwendenlet
als führendes Schlüsselwort. 🎜🎜......🎜🎜Sie deklarieren eine Vorlagenvariable input in einer Vorlage mit dem Schlüsselwortlet
(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. 🎜🎜...🎜
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: '[appRepeat]', }) 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, }); }); } }
*ngFor
-Direktive. trackBy
Dies ähnelt dem Schlüssel in Vue und React. Sie können der Vorlage eine Kennung zuweisen, um den Leistungsaufwand beim erneuten Rendern zu reduzieren. 🎜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
let-i
undlet-odd
Variablen werden durchlet i=index
undlet odd=odd
definiert. Angular setzt sie auf die aktuellen Werte der Eigenschaftenindex
undodd
im Objekt Context.- Das Kontextattribut von
let-hero
wird hier nicht angegeben. Sein Ursprung ist implizit. Angular setztlet-hero
in diesem Kontext auf den Wert der Eigenschaft$implicit
, die vonNgFor
mit dem Helden in der aktuellen Iteration initialisiert wird .
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-a
,let-b
,let-c
还是let-me
。声明的这个变量的值都等于$implicit
的值。而我们进行赋值过的,比如let-i = "index"
,i
的值就等于这个上下文对象中的index
属性对应的值。
当我们知道这个上下文对象是什么了,就该想这个上下文对象是怎么设置的了。
在结构性指令这一节当中,我们跟着官方示例做了一遍这个自定义结构性指令(如果还没有做的话,建议先跟着做一遍)。在UnlessDirective
这个指令中,其构造器constructor
声明了两个可注入的变量,分别是TemplateRef
和ViewContainerRef
。官网给的解释我觉得太过晦涩难懂,我这里给出一下我自己的理解:TemplateRef
代表的是宿主元素被包裹之后形成的模板的引用。而ViewContainerRef
代表的是一个视图容器的引用。那么问题来了,这个视图容器在哪儿呢?我们在constructor
构造器中打印一下ViewContainerRef
。打印结果如图:
然后我们点进去这个comment
元素。发现其就是一个注释元素。如图所示:
其实我也不是很确定这个视图容器到底是不是这个注释元素。但是毋庸置疑的是,视图容器和宿主元素是兄弟关系,紧挨着宿主元素。我们可以使用ViewContainerRef
中的createEmbeddedView()
方法(Embedded:嵌入式,内嵌式),将templateRef
模板引用传入进去,创建出来一个真实的视图。由于这个视图是被插入到视图容器ViewContainerRef
中了,所以又叫内嵌视图。那么这又和我们的上下文对象有什么关系呢?其实createEmbeddedView
这个方法不止一个参数,其第二个参数就是给我们的模板设置上下文对象的。API的详情介绍请看createEmbeddedView这个API的详情。
就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用let声明变量的方法来使用这个上下文对象了。
appRepeat
那么我们知道是如何设置的了,那么我们就来验证一下是否是对的。接下来,我们仿照ngfor
的功能,自己写一个简单的渲染指令。
首先我们定义一个指令:RepeatDirective
。代码如下:
@Directive({ selector: '[appRepeat]', }) 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: 'app-structural-likeNgFor-demo', 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[] = ['钟离', '烟绯', '诺艾尔', '迪奥娜']; }
在这里需要注意的是指令中的appRepeatOf
不是乱写的。在微语法的解析过程中let h of heroesList
中的of
首先首字母会变成大写的,变成Of
。然后在给它加上这个指令的前缀,也就是appRepeat
。组合起来就是appRepeatOf
了。由它来接收一个可迭代的对象。
最后显示的效果图:
运行结果的话和*ngFor
没有区别。但是功能肯定是欠缺的,如果有能力的小伙伴可以去阅读*ngFor
的源码:*ngFor的源码。
Durch diesen Artikel wissen wir, dass die let-variable
let-变量
这个模板输入变量是通过模板的上下文对象中定义并获取值的。然后想要设置上下文对象的话需要通过createEmbeddedView
方法的第二个参数来设置。
但是我总觉得了解的还不够透彻,我总觉得设置模板的上下文对象可能不只是createEmbeddedView
Vorlageneingabevariable
KontextobjektEinführung in die Programmierungder Vorlage erhält. Wenn Sie dann das Kontextobjekt festlegen möchten, müssen Sie es über den zweiten Parameter der Methode
Aber ich habe immer das Gefühl, dass das Verständnis nicht gründlich genug ist. Ich habe immer das Gefühl, dass dascreateEmbeddedView
festlegen.Kontext
-Objekt, das die Vorlage festlegt, möglicherweise nicht nurist 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. 🔜 :
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!