Angular のテンプレート入力変数 (let 変数) について話しましょう

青灯夜游
リリース: 2021-07-14 10:41:00
転載
2137 人が閲覧しました

Angular のテンプレート入力変数 (let 変数) について話しましょう

私は、記事を書いたり、自分の経験を共有したりするときに、公式 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="&#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 が何なのかを公式 Web サイトで探し始めました。最後に、主要概念 - 命令 - 構造命令 マイクログラマー セクションで let に関する説明を見つけました。公式ウェブサイトの説明: Microgrammar

以下に簡単な説明もあります:

テンプレート入力変数

テンプレート入力変数 は次のようなものです 値を取得できる変数単一インスタンスのテンプレート内の参照。この例には、heroiodd といういくつかのテンプレート入力変数があります。これらはすべて、先頭のキーワードとして let を使用します。

....

let キーワード (let hero など) を使用して、テンプレート 入力をテンプレート内で宣言します。 ) ###変数。この変数のスコープは、繰り返されるテンプレートの 単一インスタンスに制限されます。実際、他の構造ディレクティブでも同じ変数名を使用できます。 ....

公式ウェブサイトは相変わらず非言語的で、ほんの数文で紹介されており、その方法については説明されていません。また、
let

で宣言された変数の値がどこから来たのかもわかりません。読めば読むほど腹が立ったので、公式サイトを教えてくれなかったら自分で探します。 大まかな結論から始めましょう:

let によって宣言された変数は、このテンプレート テンプレートのコンテキスト オブジェクト内の変数

です。それ以外の場合、なぜ テンプレート入力変数 と呼ばれるのでしょうか? *ngFor Insider セクションでは、内部ストーリーを学びました。構造ディレクティブは実際にホスト要素を でラップしており、次に、このテンプレートの *ngFor の式を解析して、各 let テンプレート入力変数と、この命令に渡す必要がある値を入れます。テンプレート内のコードはビューに直接レンダリングされないため、テンプレートをビューに変換する何らかの方法が必要です。構造ディレクティブはまさにそれを行い、テンプレートをビューに変換します。

*ngFor

の公式サンプル コードは次のとおりです。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">//解析前的模板 &lt;div *ngFor=&quot;let hero of heroes; let i=index; let odd=odd; trackBy: trackById&quot; [class.odd]=&quot;odd&quot;&gt; ({{i}}) {{hero.name}} &lt;/div&gt; //angular解析后的模板 &lt;ng-template ngFor let-hero [ngForOf]=&quot;heroes&quot; let-i=&quot;index&quot; let-odd=&quot;odd&quot; [ngForTrackBy]=&quot;trackById&quot;&gt; &lt;div [class.odd]=&quot;odd&quot;&gt;({{i}}) {{hero.name}}&lt;/div&gt; &lt;/ng-template&gt;</pre><div class="contentsignin">ログイン後にコピー</div></div>

念のため、いわゆる
    host 要素
  • は次のとおりです。命令が配置されている要素。上記の例のように、div*ngFor ディレクティブのホスト要素です。
  • trackBy
  • これは、vue および React のキーに似ています。テンプレートに識別子を与えると、再レンダリング時のパフォーマンスのオーバーヘッドを軽減できます。
  • それでは、公式 Web サイトの内容を見てみましょう:

    let-i
  • let-odd変数は、let i=index および let odd=odd によって定義されます。 Angular は、これらを context オブジェクトの index プロパティと odd プロパティの現在の値に設定します。
  • let-hero
  • の context 属性はここでは指定されていません。その起源は暗黙的です。 Angular は、このコンテキストで let-hero$implicit プロパティの値に設定します。このプロパティは、現在の反復でヒーローを使用して NgFor によって初期化されます。
この説明を読むと、
angular はこのテンプレートのコンテキスト オブジェクト

を設定することがわかります。ただし、このプロセスは ngFor のソース コード内に実装されているため、見ることができません。そして、この context オブジェクト には index 属性と odd 属性があり、$implicit (暗黙的: 暗黙的。直接は記述されていません) プロパティが含まれています。次に、この コンテキスト オブジェクト には少なくとも次の属性があると推測します:

{
    $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。打印结果如图:

Angular のテンプレート入力変数 (let 変数) について話しましょう

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

Angular のテンプレート入力変数 (let 変数) について話しましょう

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

Angular のテンプレート入力変数 (let 変数) について話しましょう

就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用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了。由它来接收一个可迭代的对象。

最后显示的效果图:

Angular のテンプレート入力変数 (let 変数) について話しましょう

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

概要

この記事を通じて、let-variableこの テンプレート入力変数がテンプレートを介して渡されることがわかりましたコンテキストオブジェクト で定義され、値を取得します。次に、コンテキスト オブジェクトを設定する場合は、createEmbeddedView メソッドの 2 番目のパラメーターを使用して設定する必要があります。

結論

しかし、理解が十分ではないといつも感じています。テンプレートを設定する context オブジェクトが正しく理解されていない可能性があるといつも感じています。 createEmbeddedView これはメソッドですが、他のメソッドは見つかりませんでした。他の方法をご存知の方がいらっしゃいましたら、メッセージを残してお知らせください。

参考資料:

この記事は次の影響を受けています: Angular は "repeat" ディレクティブを実装します

転載アドレス: https:// juejin.cn/post/6956466729891561503

プログラミング関連の知識については、プログラミング入門をご覧ください。 !

以上がAngular のテンプレート入力変数 (let 変数) について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート