模板简介

应用程序中的每个 Angular 模板都是一块 HTML,Angular 中的 HTML 模板与常规 HTML 一样,可以在浏览器中渲染视图或用户界面,但功能要多得多,比如Angular 可以通过内置的模板函数、变量、事件监听和数据绑定等功能来帮助你动态获取和设置 DOM(文档对象模型)中的值。

文本插值

将动态字符串值合并到 HTML 模板中。优点:可以动态更改应用视图中显示的内容。

使用插值语法显示值

  1. <label>Company Name: {{ companyName }}</label>
  2. <img src="{{ imageUrl }}">

模板表达式

Angular 解析该表达式并将其赋值给绑定目标的某个属性。目标可以是 HTML 元素、组件或指令。

  1. <p>{{ 1 + 1 }}</p>
  2. <!-- 2 -->
  3. <p>{{ '1' + 1 }}</p>
  4. <!-- 11 -->
  5. <p>{{1 + getTen()}}</p>
  6. getTen() {
  7. return 10
  8. }
  9. <!-- 11 -->
  10. <!-- 报错 -->
  11. <p>{{ 1 - '1' }}</p>
  12. <p>{{1 + Math.random()*10}}</p>
  13. <!-- 模板表达式不能引用全局命名空间中的任何东西,比如 window 或 document。它们也不能调用 console.log 或 Math.max。 它们只能引用表达式上下文中的成员。 -->

不支持包括:

  • 赋值 (=, +=, -=, …)
  • 运算符,比如 new、typeof 或 instanceof 等。
  • 使用 ; 或 , 串联起来的表达式
  • 自增和自减运算符:++ 和 —
  • 一些 ES2015+ 版本的运算符
  • 不支持位运算,比如 | 和 &
  • 新的模板表达式运算符,例如 |,?. 和 !

表达式上下文

组件实例

  1. <label>Company Name: {{ companyName }}</label>
  2. <img src="{{ imageUrl }}">

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

模板输入变量

  1. <div *ngFor="let item of imageList">
  2. <img src="{{ item }}">
  3. </div>

模板引用变量

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

防止命名冲突

Angular 将应用以下逻辑来确定上下文:

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

规则

  • 使用短表达式:尽可能使用属性名称或方法调用
  • 快速执行:尽快完成,以保持用户体验的性能
  • 没有可见的副作用:视图应在整个渲染过程中保持稳定

代替{{ }}

interpolation?: [string, string]

  1. @Component({
  2. selector: 'xxxx',
  3. templateUrl: './xxxx.component.html',
  4. styleUrls: [ './xxxx.component.less' ],
  5. interpolation: ["((","))"]
  6. })

模板语句

模板语句是可在 HTML 中用于响应用户事件的方法或属性。使用模板语句,你的应用可以通过诸如显示动态内容或提交表单之类的动作吸引用户。

  1. <button (click)="helloWorld()">Hello Word</button>
  2. <!-- 这里的helloWorld()就是模板语句 -->

不支持:

  • new
  • 递增和递减运算符 ++ 和 —
  • 赋值运算符,例如 += 和 -=
  • 按位运算符,例如 | 和 &
  • 管道操作符

语句上下文

组件实例

  1. <button (click)="helloWorld()">Hello Word</button>

模板自身属性

  1. <button (click)="clickBtn($event)">Btn</button>

模板输入变量

  1. <button *ngFor="let imageUrl of imageList" (click)="showImgUrl(imageUrl)">{{imageUrl}}</button>

模板引用变量

  1. <input #customerInput (keyup)="0">
  2. <!-- (keyup)="0"使angular更新屏幕 -->
  3. <button (click)="showCustomerInput(customerInput)">customerInput</button>

规则

  • 简明:只使用方法调用或基本属性赋值,让模板语句最少化
  • 在上下文中工作:模板语句无法引用全局名称空间中的任何内容,例如 window 或 document。例如,模板语句不能调用 console.log() 或 Math.max()

管道

管道是一些简单的函数,可以在模板表达式中用来接受输入值并返回一个转换后的值。

Angular 为典型的数据转换提供了内置的管道,数据格式化常用的内置管道如下:

  • DatePipe:根据本地环境中的规则格式化日期值。
  • UpperCasePipe:把文本全部转换成大写。
  • LowerCasePipe :把文本全部转换成小写。
  • CurrencyPipe :把数字转换成货币字符串,根据本地环境中的规则进行格式化。
  • DecimalPipe:把数字转换成带小数点的字符串,根据本地环境中的规则进行格式化。
  • PercentPipe :把数字转换成百分比字符串,根据本地环境中的规则进行格式化。

基本用法

  1. <p>{{ nowDate | date }}</p>
  2. nowDate = new Date();

使用参数和管道链来格式化数据

  1. <!-- 用可选参数微调管道的输出 -->
  2. {{ amount | currency:'EUR' }} // €1,000.00
  3. <!-- 如果管道能接受多个参数,就用冒号分隔这些值。 -->
  4. {{ amount | currency:'EUR':'Euros '}} // Euros 1,000.00
  5. <!-- SlicePipe从一个 Array 或 String 中创建其元素一个新子集(slice)。 -->
  6. {{ '12345' | slice:1:3 }} // 23
  7. {{ ['1', '2', '3', '4', '5'] | slice:1:3 }} // 2,3
  8. <!-- 参数还可以是一个函数 -->
  9. <p>{{ nowDate | date:format }}</p>
  10. <button (click)="toggle = !toggle">Toggle Date</button>
  11. get format(){
  12. return this.toggle ? 'shortDate' : 'fullDate';
  13. }

通过串联管道应用两种格式

  1. <p>{{ nowDate | date | uppercase }}</p>
  2. <!-- 注意逻辑顺序,以下顺序会报错 -->
  3. <!-- <p>{{ nowDate | uppercase | date }}</p> -->

创建自定义管道

  1. ng g pipe <pipeName>

在产生的.pipe.ts文件里,添加管道逻辑。

检测变更

通过默认情况下,管道会定义成纯的(pure),这样 Angular 只有在检测到输入值发生了纯变更时才会执行该管道。纯变更是对原始输入值(比如 String、Number、Boolean 或 Symbol )的变更,或是对对象引用的变更(比如 Date、Array、Function、Object)。
使用纯管道,Angular 会忽略复合对象中的变化。如果修改了输入数组,纯管道就不会执行。如果替换了输入数组,就会执行该管道并更新显示。

检测复合对象中的非纯变更

要在复合对象内部进行更改后执行自定义管道(例如更改数组元素),就需要把管道定义为 impure 以检测非纯的变更。每当按键或鼠标移动时,Angular 都会检测到一次变更,从而执行一个非纯管道。

  1. @Pipe({
  2. name: 'xxxxx',
  3. pure: false
  4. })
  • 虽然非纯管道很实用,但要小心使用。长时间运行非纯管道可能会大大降低你的应用速度。

管道优先级

管道操作符要比三目运算符(?:)的优先级高,这意味着 a ? b : c | x 会被解析成 a ? b : (c | x)。
由于这种优先级设定,如果你要用管道处理三目元算符的结果,就要把整个表达式包裹在括号中,比如 (a ? b : c) | x。

属性绑定

Angular 中的属性绑定可帮助你设置 HTML 元素或指令的属性值。

方括号 [] 使 Angular 将等号的右侧看作动态表达式进行求值

  1. <input [id]="title">

不使用方括号,Angular 就会将右侧视为字符串字面量并将此属性设置为该静态值

  1. <input id="title">

设置指令属性

Angular 会将 special 类应用到

  1. <label [ngClass]="classes"></label>
  2. classes = 'special';

组件之间绑定

  1. <child-demo [childItem]="parentItem"></child-demo>

安全性

这里不会处理 HTML,而是原样显示它

  1. <p>{{ riskStr }}</p>
  2. riskStr = 'KPMG Company<script>alert("hahahaha")</script>NJ KDI'
  3. <!-- KPMG Company<script>alert("hahahaha")</script>NJ KDI -->
  4. <!-- Angular 不允许带有 <script> 标记的 HTML,既不能用于插值也不能用于属性绑定 -->

无害化

  1. <p [innerHTML]="riskStr"></p>
  2. riskStr = 'KPMG Company<script>alert("hahahaha")</script>NJ KDI'
  3. <!-- KPMG CompanyNJ KDI -->

属性绑定和插值

插值和属性绑定可以达到相同的结果。以下绑定会做相同的事

  1. <img [src]="imageUrl">
  2. <img src="{{imageUrl}}">
  • 将数据值渲染为字符串时,可以使用任一种形式,只是插值形式更易读。但是,要将元素属性设置为非字符串数据值时,必须使用属性绑定。

Attribute、class、style绑定

Attribute绑定

有时你没有可绑定的元素 Property。在这种情况下,可以使用 Attribute 绑定。(ARIA/SVG)
ARIA:

  1. <button [attr.aria-label]="title">{{title}} with Aria</button>
  2. <table border='1'>
  3. <tr><td [attr.colspan]="1 + 1">合并单元格</td></tr>
  4. <tr><td>1</td><td>2</td></tr>
  5. </table>

单class绑定

  1. <div [class.active]="active"></div>

多class绑定

  1. <!-- 字符串 -->
  2. <div [class]="'redBorder blueBackground'"></div>
  3. <!-- 数组 -->
  4. <div [class]="['redBorder', 'blueBackground']"></div>
  5. <!-- 对象 -->
  6. <div [class]="{redBorder:true, blueBackground:true}"></div>
  • 对于任何类似对象的表达式(例如 object、Array、Map 或 Set,必须更改对象的引用,Angular 才能更新类列表。在不更改对象引用的情况下只更新其 Attribute 是不会生效的。

单style绑定

  1. <div [style.background-color]="'lightblue'"></div>

多style绑定

  1. <div [style]="'width:100px;height:100px;background:lightblue'"></div>
  2. <div [style]="{width:'100px',height:'100px',background:'lightblue',marginTop:'10px'}"></div>
  • 不支持把数组绑定给 [style]
  • 当把 [style] 绑定到对象表达式时,该对象的引用必须改变,这样 Angular 才能更新这个类列表。在不改变对象引用的情况下更新其属性值是不会生效的。

注入属性值

场景:需要知道