聊聊Angular中的模板输入变量(let-变量)
我这个人,写文章或者说心得,不喜欢直接抄官网上面的东西,实在是没啥意思。我还是喜欢用我的大白话来写文章。今天这个关于模板输入变量的这个我今天啃官网啃了许久,总算是初步的了解了是啥东西。【相关教程推荐:《angular教程》】
那么模板输入变量到底是什么
我想研究这玩意的起因在于之前我使用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="'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
(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的详情。
就这样。我们就可以将上下文对象塞入模板中了,这样的话我们也可以直接使用let声明变量的方法来使用这个上下文对象了。
自定义一个简单的类*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, }); }); } }
然后我们将其导入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的源码。
总结
通过这篇文章,我们知道了let-变量
这个模板输入变量是通过模板的上下文对象中定义并获取值的。然后想要设置上下文对象的话需要通过createEmbeddedView
方法的第二个参数来设置。
结语
但是我总觉得了解的还不够透彻,我总觉得设置模板的上下文对象可能不只是createEmbeddedView
这一种方法,但是我并没有找到其他的方法。如果各位小伙伴有知道其他的方法可以留言告诉我。
参考资料:
这篇文章灵感来自:Angular 实现一个"repeat" 指令
转载地址:https://juejin.cn/post/6956466729891561503
更多编程相关知识,请访问:编程入门!!
以上是聊聊Angular中的模板输入变量(let-变量)的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

环境变量是运行应用和程序的位置路径(或环境)。它们可以由用户创建、编辑、管理或删除,并在管理某些进程的行为时派上用场。下面介绍如何创建配置文件以同时管理多个变量,而无需在Windows上单独编辑它们。如何在环境变量中使用配置文件Windows11和10在Windows上,有两组环境变量–用户变量(应用于当前用户)和系统变量(全局应用)。但是,使用像PowerToys这样的工具,您可以创建一个单独的配置文件来添加新的和现有的变量并一次管理它们。方法如下:步骤1:安装PowerToysPowerTo

Angular.js是一种可自由访问的JavaScript平台,用于创建动态应用程序。它允许您通过扩展HTML的语法作为模板语言,以快速、清晰地表示应用程序的各个方面。Angular.js提供了一系列工具,可帮助您编写、更新和测试代码。此外,它还提供了许多功能,如路由和表单管理。本指南将讨论在Ubuntu24上安装Angular的方法。首先,您需要安装Node.js。Node.js是一个基于ChromeV8引擎的JavaScript运行环境,可让您在服务器端运行JavaScript代码。要在Ub

PHP7中引入了严格模式,该模式可以帮助开发者减少潜在的错误。本文将介绍什么是严格模式以及如何在PHP7中使用严格模式来减少错误。同时,将通过代码示例演示严格模式的应用。一、什么是严格模式?严格模式是PHP7中的一个特性,它可以帮助开发者编写更规范的代码,减少一些常见的错误。在严格模式下,会对变量的声明、类型检查、函数调用等进行严格的限制和检测。通

Angular框架中组件的默认显示行为不是块级元素。这种设计选择促进了组件样式的封装,并鼓励开发人员有意识地定义每个组件的显示方式。通过显式设置CSS属性 display,Angular组件的显示可以完全控制,从而实现所需的布局和响应能力。

Java中的实例变量是指定义在类中,而不是方法或构造函数中的变量。实例变量也称为成员变量,每个类的实例都有自己的一份实例变量副本。实例变量在创建对象的过程中被初始化,以及在对象的生命周期中保存并保持其状态。实例变量的定义通常放在类的顶部,可以用任何访问修饰符来声明,可以是public、private、protected或默认访问修饰符。这取决于我们希望这个变

身份验证是任何Web应用程序中最重要的部分之一。本教程讨论基于令牌的身份验证系统以及它们与传统登录系统的区别。在本教程结束时,您将看到一个用Angular和Node.js编写的完整工作演示。传统身份验证系统在继续基于令牌的身份验证系统之前,让我们先看一下传统的身份验证系统。用户在登录表单中提供用户名和密码,然后点击登录。发出请求后,通过查询数据库在后端验证用户。如果请求有效,则使用从数据库中获取的用户信息创建会话,然后在响应头中返回会话信息,以便将会话ID存储在浏览器中。提供用于访问应用程序中受

使用Ajax从PHP方法中获取变量是Web开发中常见的场景,通过Ajax可以实现页面无需刷新即可动态获取数据。在本文中,将介绍如何使用Ajax从PHP方法中获取变量,并提供具体的代码示例。首先,我们需要编写一个PHP文件来处理Ajax请求,并返回所需的变量。下面是一个简单的PHP文件getData.php的示例代码:

python凭借其简单易读的语法,广泛应用于广泛的领域中。掌握Python语法的基础结构至关重要,既可以提高编程效率,又能深入理解代码的运作方式。为此,本文提供了一个全面的思维导图,详细阐述了Python语法的各个方面。变量和数据类型变量是Python中用于存储数据的容器。思维导图展示了常见的Python数据类型,包括整数、浮点数、字符串、布尔值和列表。每个数据类型都有其自身的特性和操作方法。运算符运算符用于对数据类型执行各种操作。思维导图涵盖了Python中的不同运算符类型,例如算术运算符、比
