>웹 프론트엔드 >JS 튜토리얼 >Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.

Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.

青灯夜游
青灯夜游앞으로
2021-07-14 10:40:312181검색

Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.

저는 기사를 쓰거나 내 경험을 이야기하는 사람입니다. 공식 홈페이지에서 직접 복사하는 것은 정말 의미가 없습니다. 나는 아직도 모국어로 기사를 쓰는 것을 좋아합니다. 오늘 공식 홈페이지에서 템플릿 입력 변수에 대한 내용을 오랜 시간 읽어보고 드디어 그것이 무엇인지 예비적으로 이해하게 되었습니다. [관련 튜토리얼 추천 : "angular tutorial"]

템플릿 입력 변수란 정확히 무엇인가요

제가 이걸 공부하고 싶은 이유는 예전에 ng-zorro를 사용할 때 페이징을 사용했기 때문입니다. 구성요소 페이지 매김(공식 웹사이트 링크Pagination官网链接)。这其中有一个自定义上一页下一页模板的功能。代码的话如下:

@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). 이전 페이지와 다음 페이지 템플릿을 맞춤설정하는 기능이 있습니다. 코드는 다음과 같습니다.

{
    $implicit:null,
    index:null,
    odd:null,
}
🎜이 글을 읽고 나서 저는 매우 혼란스러웠습니다. 이것이 let이 무엇인지, 왜 let-에 변수가 뒤따르고 값이 있는 걸까요? 그러다가 공식 홈페이지에서 이 let가 무엇인지 찾기 시작했습니다. 드디어 🎜주요 개념 - 명령어 - 구조적 명령어🎜의 🎜Microgrammar🎜섹션에서 let에 대한 설명을 찾았습니다. 공식 웹사이트 설명: 마이크로 구문 🎜. 🎜🎜아래에 간단한 설명도 있습니다. 🎜
🎜템플릿 입력 변수 🎜🎜템플릿 입력 변수단일 인스턴스에서 해당 값을 참조할 수 있는 변수입니다. em>템플릿입니다. 이 예에는 hero, iodd 등 여러 가지 템플릿 입력 변수가 있습니다. 그들은 모두 let를 주요 키워드로 사용합니다. 🎜🎜......🎜🎜 let 키워드(예: let Hero)를 사용하여 템플릿에서 템플릿 입력 변수를 선언합니다. . 이 변수의 범위는 반복되는 템플릿의 단일 인스턴스로 제한됩니다. 실제로 다른 구조 지시문에서도 동일한 변수 이름을 사용할 수 있습니다. 🎜🎜...🎜
🎜공식 홈페이지는 여전히 여전히 비언어적입니다. 단 몇 문장으로 사용법을 알려주지도 않고, 알려주지도 않습니다. let으로 선언된 변수의 값은 어디에서 왔습니까? 더 많이 읽을수록 더 화가 났어요. 공식 홈페이지에 대해 알려주지 않으면 제가 직접 찾아보겠습니다. 🎜🎜대략적인 결론부터 시작해 보겠습니다. 🎜let으로 선언된 변수는 이 템플릿 템플릿🎜의 컨텍스트 개체에 있는 변수입니다. 그렇지 않으면 왜 🎜템플릿 입력 변수🎜라고 불리는 걸까요? *🎜ngFor Insider🎜 섹션에서 구조적 지시어가 실제로 <ng-template></ng-template>에 호스트 요소를 래핑하는 내부 이야기를 배웠습니다. 템플릿에서 *ngFor의 표현식은 각 let 템플릿 입력 변수와 이 지시어에 전달되어야 하는 값으로 구문 분석됩니다. 템플릿의 코드는 뷰로 직접 렌더링되지 않으므로 템플릿을 뷰로 전환할 수 있는 방법이 있어야 합니다. 우리의 구조적 지시문이 바로 그 일을 하며 템플릿을 뷰로 전환합니다. 🎜🎜*ngFor의 공식 샘플 코드는 다음과 같습니다. 🎜
@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,
      });
    });
  }
}
  • 참고로 소위 🎜host 요소🎜는 명령어가 위치한 요소입니다. 위의 예에서 div는 *ngFor 지시문의 호스트 요소입니다.
  • trackBy 이는 vue 및 React의 키와 유사합니다. 템플릿을 다시 렌더링할 때 성능 오버헤드를 줄이기 위해 템플릿에 식별자를 제공할 수 있습니다.
🎜그럼 공식 웹사이트에 나와 있는 내용을 살펴보겠습니다: 🎜
  • let-ilet-odd 변수는 let i=indexletodd=odd로 정의됩니다. Angular는 이를 Context 객체의 indexodd 속성의 현재 값으로 설정합니다.
  • let-hero의 컨텍스트 속성은 여기에 지정되지 않습니다. 그 기원은 암시적입니다. Angular는 let-hero를 이 컨텍스트의 $implicit 속성 값으로 설정합니다. 이 속성은 현재 반복에서 Hero를 사용하여 NgFor에 의해 초기화됩니다. .
🎜이 설명을 읽고 나면 다음을 알 수 있습니다. 🎜angular는 이 템플릿에 대한 컨텍스트 개체🎜를 설정합니다. 하지만 이 프로세스는 ngFor의 소스 코드 내부에 구현되어 있기 때문에 볼 수 없습니다. 그리고 이 🎜Context 개체🎜에는 indexodd 속성이 있고 $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-variables)에 대해 이야기해 보겠습니다.

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

Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.

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

Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.

就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用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-variables)에 대해 이야기해 보겠습니다.

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

요약

이 글을 통해 우리는 let-variable let-变量这个模板输入变量是通过模板的上下文对象中定义并获取值的。然后想要设置上下文对象的话需要通过createEmbeddedView方法的第二个参数来设置。

结语

但是我总觉得了解的还不够透彻,我总觉得设置模板的上下文对象可能不只是createEmbeddedView템플릿 입력 변수

가 정의되어 있고 템플릿의
컨텍스트 개체

를 통해 값을 가져오는 것을 알 수 있습니다. 그런 다음 컨텍스트 개체를 설정하려면 createEmbeddedView 메서드의 두 번째 매개변수를 통해 설정해야 합니다.

결론

하지만 템플릿을 설정하는

context

객체가 단지 가 아닐 수도 있다는 생각이 항상 듭니다. createEmbeddedView 한 가지 방법이지만 다른 방법은 찾지 못했습니다. 다른 방법을 아시는 분은 메시지를 남겨 알려주세요.

참고 자료:

이 기사는 다음에서 영감을 받았습니다: 🎜Angular는 "반복" 지침을 구현합니다.🎜🎜🎜재인쇄 주소: https://juejin.cn/post/6956466729891561503🎜🎜🎜더 많은 프로그래밍 관련 지식을 보려면 다음을 방문하세요. : 🎜프로그래밍 입문🎜! ! 🎜

위 내용은 Angular의 템플릿 입력 변수(let-variables)에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제