私は、記事を書いたり、自分の経験を共有したりするときに、公式 Web サイトからのものを直接コピーするのは好きではありません。私は今でも自分の言葉で記事を書くのが好きです。今日、公式 Web サイトで テンプレート入力変数 について長い時間を費やし、ようやくそれが何であるかを予備的に理解しました。 [関連チュートリアルの推奨事項: "angular チュートリアル"]
これを研究したい理由以前は ng-zorro を使用していたとき、そのページング コンポーネント Pagination
(公式 Web サイトのリンク ) を使用していました。 前のページと次のページのテンプレートをカスタマイズする関数があります。コードは次のとおりです:
@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
が何なのかを公式 Web サイトで探し始めました。最後に、主要概念 - 命令 - 構造命令 の マイクログラマー セクションで let
に関する説明を見つけました。公式ウェブサイトの説明: Microgrammar。
以下に簡単な説明もあります:
letテンプレート入力変数
テンプレート入力変数 は次のようなものです 値を取得できる変数単一インスタンスのテンプレート内の参照。この例には、hero
....、
i、
oddといういくつかのテンプレート入力変数があります。これらはすべて、先頭のキーワードとして
letを使用します。
let
公式ウェブサイトは相変わらず非言語的で、ほんの数文で紹介されており、その方法については説明されていません。また、キーワード (
let heroなど) を使用して、テンプレート
入力をテンプレート内で宣言します。 ) ###変数。この変数のスコープは、繰り返されるテンプレートの 単一インスタンスに制限されます。実際、他の構造ディレクティブでも同じ変数名を使用できます。 ....
で宣言された変数の値がどこから来たのかもわかりません。読めば読むほど腹が立ったので、公式サイトを教えてくれなかったら自分で探します。 大まかな結論から始めましょう:
です。それ以外の場合、なぜ テンプレート入力変数 と呼ばれるのでしょうか? *ngFor Insider セクションでは、内部ストーリーを学びました。構造ディレクティブは実際にホスト要素を *ngFor
の式を解析して、各 let
テンプレート入力変数と、この命令に渡す必要がある値を入れます。テンプレート内のコードはビューに直接レンダリングされないため、テンプレートをビューに変換する何らかの方法が必要です。構造ディレクティブはまさにそれを行い、テンプレートをビューに変換します。
の公式サンプル コードは次のとおりです。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">//解析前的模板
<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></pre><div class="contentsignin">ログイン後にコピー</div></div>
*ngFor
ディレクティブのホスト要素です。
angular はこのテンプレートのコンテキスト オブジェクトlet-i
この説明を読むと、- と
let-herolet-odd
変数は、let i=index
およびlet odd=odd
によって定義されます。 Angular は、これらをcontext
オブジェクトの index プロパティとodd
プロパティの現在の値に設定します。- の context 属性はここでは指定されていません。その起源は暗黙的です。 Angular は、このコンテキストで
let-hero
を$implicit
プロパティの値に設定します。このプロパティは、現在の反復でヒーローを使用してNgFor
によって初期化されます。
を設定することがわかります。ただし、このプロセスは ngFor のソース コード内に実装されているため、見ることができません。そして、この 那么我们声明 当我们知道这个上下文对象是什么了,就该想这个上下文对象是怎么设置的了。 在结构性指令这一节当中,我们跟着官方示例做了一遍这个自定义结构性指令(如果还没有做的话,建议先跟着做一遍)。在 然后我们点进去这个 其实我也不是很确定这个视图容器到底是不是这个注释元素。但是毋庸置疑的是,视图容器和宿主元素是兄弟关系,紧挨着宿主元素。我们可以使用 就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用let声明变量的方法来使用这个上下文对象了。 那么我们知道是如何设置的了,那么我们就来验证一下是否是对的。接下来,我们仿照 首先我们定义一个指令: 然后我们将其导入NgModule中,这个过程就省略不写了。然后我们在组件中使用一下这个指令: 在这里需要注意的是指令中的 最后显示的效果图: 运行结果的话和 この記事を通じて、 しかし、理解が十分ではないといつも感じています。テンプレートを設定する context オブジェクトが正しく理解されていない可能性があるといつも感じています。 参考資料: この記事は次の影響を受けています: Angular は "repeat" ディレクティブを実装します 転載アドレス: https:// juejin.cn/post/6956466729891561503 プログラミング関連の知識については、プログラミング入門をご覧ください。 ! 以上がAngular のテンプレート入力変数 (let 変数) について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。context オブジェクト
には index 属性と odd
属性があり、$implicit
(暗黙的: 暗黙的。直接は記述されていません) プロパティが含まれています。次に、この コンテキスト オブジェクト
には少なくとも次の属性があると推測します:{
$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的详情。自定义一个简单的类*ngFor指令——
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,
});
});
}
}
@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的源码。概要
let-variable
この テンプレート入力変数がテンプレートを介して渡されることがわかりましたコンテキストオブジェクト で定義され、値を取得します。次に、コンテキスト オブジェクトを設定する場合は、createEmbeddedView
メソッドの 2 番目のパラメーターを使用して設定する必要があります。 結論
createEmbeddedView
これはメソッドですが、他のメソッドは見つかりませんでした。他の方法をご存知の方がいらっしゃいましたら、メッセージを残してお知らせください。