阅读(4046) (0)

Angular 文本插值

2022-06-28 10:41:09 更新

文本插值

文本插值允许你将动态字符串值合并到 HTML 模板中。通过插值,你可以动态更改应用视图中显示的内容,例如显示包含用户名的自定义问候语。

要了解本指南中涉及的语法和代码片段,请参阅 现场演练 / 下载范例。

使用插值语法显示值

插值是指将表达式嵌入到被标记的文本中。默认情况下,插值使用双花括号 ​{{​ 和 ​}}​ 作为定界符。

为了说明插值的工作原理,请考虑一个包含 ​currentCustomer ​变量的 Angular 组件:

currentCustomer = 'Maria';

可以用插值在相应的组件模板中显示此变量的值:

<h3>Current customer: {{ currentCustomer }}</h3>

Angular 会用相应组件属性的字符串值替换掉 ​currentCustomer​。在这里,它的值是 ​Maria​。

在以下示例中,Angular 会求出 ​title ​和 ​itemImageUrl ​属性的值,以显示一些标题文本和图像。

<p>{{title}}</p>
<div><img src="{{itemImageUrl}}"></div>

模板表达式

模板表达式会产生一个值,它出现在双花括号 ​{{ }}​ 中。 Angular 解析该表达式并将其赋值给绑定目标的某个属性。目标可以是 HTML 元素、组件或指令。

用插值解析表达式

一般来说,括号间的文本是一个模板表达式,Angular 先对它求值,再把它转换成字符串。 下列插值通过把括号中的两个数字相加说明了这一点:

<!-- "The sum of 1 + 1 is 2" -->
<p>The sum of 1 + 1 is {{1 + 1}}.</p>

这些表达式也可以调用宿主组件的方法,就像下面用的 ​getVal()​:

<!-- "The sum of 1 + 1 is not 4" -->
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}.</p>

通过插值,Angular 执行以下任务:

  1. 计算所有位于双花括号中的表达式。
  2. 将这些表达式的结果转换为字符串。
  3. 将这些结果融入相邻的字符串文本中。
  4. 将融合后的结果赋值给元素或指令的属性。

如果你想用别的分隔符来代替 ​{{​ 和 ​}}​,也可以通过 ​@Component()​ 元数据中的 ​interpolation ​选项来配置插值分隔符。

语法

模板表达式和 JavaScript 很相似。许多 JavaScript 表达式都是合法的模板表达式,但以下情况除外。

你不能使用那些具有或可能引发副作用的 JavaScript 表达式,包括:

  • 赋值 (​=​, ​+=​, ​-=​, ​...​)
  • 运算符,比如 ​new​、​typeof ​或 ​instanceof ​等。
  • 使用 ​;​ 或 ​,​ 串联起来的表达式
  • 自增和自减运算符:​++​ 和 ​--
  • 一些 ES2015+ 版本的运算符

和 JavaScript 语法的其它显著差异包括:

  • 不支持位运算,比如 ​|​ 和 ​&
  • 新的模板表达式运算符,例如 ​|​,​?.​ 和 ​!

表达式上下文

插值表达式具有上下文 —— 表达式所属应用中的特定部分。通常,此上下文就是组件实例。

在下面的代码片段中,表达式 ​recommended ​和 ​itemImageUrl2 ​表达式所引用的都是 ​AppComponent ​中的属性。

<h4>{{recommended}}</h4>
<img [src]="itemImageUrl2">

表达式也可以引用模板上下文中的属性。

下面的例子就使用了模板输入变量 ​customer​。

<ul>
  <li *ngFor="let customer of customers">{{customer.name}}</li>
</ul>

接下来的例子使用了模板引用变量 ​#customerInput​。

<label>Type something:
  <input #customerInput>{{customerInput.value}}
</label>

模板表达式不能引用全局命名空间中的任何东西,比如 ​window ​或 ​document​。它们也不能调用 ​console.log​ 或 ​Math.max​。 它们只能引用表达式上下文中的成员。

防止命名冲突

表达式求值的上下文是模板变量、指令的上下文对象(如果有的话)以及组件成员的并集。如果所引用的名称在多个命名空间都有,则 Angular 将应用以下逻辑来确定上下文:

  1. 模板变量的名称。
  2. 指令上下文中的名称。
  3. 组件成员的名称。

为避免变量遮盖另一个上下文中的变量,请保持变量名称唯一。在以下示例中,​AppComponent ​模板在问候 ​customer ​Padma。

然后,一个 ​ngFor ​列出了 ​customers ​数组中的每个 ​customer​。

@Component({
  template: `
    <div>
      <!-- Hello, Padma -->
      <h1>Hello, {{customer}}</h1>
      <ul>
        <!-- Ebony and Chiho in a list-->
        <li *ngFor="let customer of customers">{{ customer.value }}</li>
      </ul>
    </div>
  `
})
class AppComponent {
  customers = [{value: 'Ebony'}, {value: 'Chiho'}];
  customer = 'Padma';
}

ngFor ​中的 ​customer ​处于一个 ​<ng-template>​ 的上下文中,所以它指向的是 ​customers ​数组中的 ​customer​,在这里是 Ebony 和 Chiho。此列表中不包含 Padma,因为那个 ​ customer 位于 ​ngFor ​以外的另一个上下文中。反之,​<h1>​ 中的 ​customer ​不包括 Ebony 或 Chiho,因为该 ​customer ​的上下文是组件类,而这个类中 ​customer ​的值是 Padma。

表达式最佳实践

使用模板表达式时,请遵循以下最佳实践:

  • 使用短表达式
  • 尽可能使用属性名称或方法调用。将应用和业务逻辑保留在组件中,这里更便于开发和测试。

  • 快速执行
  • Angular 会在每个变更检测周期之后执行模板表达式。许多异步活动都会触发变更检测周期,例如解析 Promise、HTTP 结果、计时器事件、按键和鼠标移动。

    表达式应尽快完成,以保持用户体验的性能,尤其是在速度较慢的设备上。

  • 没有可见的副作用
  • 根据 Angular 的单向数据流模型,除了目标属性的值之外,模板表达式不应更改任何应用状态。读取组件值不应更改其他显示值。该视图应在整个渲染过程中保持稳定。

幂等表达式能减少副作用
幂等的表达式是最理想的,因为它没有副作用,并且可以提高 Angular 的变更检测性能。 用 Angular 术语来说,幂等表达式总会返回完全相同的东西,除非其依赖值之一发生了变化。

在单独的一次事件循环中,被依赖的值不应该改变。 如果幂等的表达式返回一个字符串或数字,如果连续调用它两次,会返回相同的字符串或数字。 如果幂等的表达式返回一个对象(包括 ​Date ​或 ​Array​),如果连续调用它两次,会返回同一个对象的引用

对于 ​*ngFor​,这种行为有一个例外。​*ngFor​ 具有 ​trackBy ​功能,在迭代对象时它可以正确处理对象值的变化。