Angular 2 模板语法

前几个章节我们已经简单接触了 angular 的模板,本章我们将深入学习 AngularJS 的模板语法

模板是用来将内容展现给用户看的部分

html

HTML 是 AngularJS 模板的 "语言",除了 <script> 元素是被禁用的外 ,其他 HTML 元素都是支持的

<h1>我的第一个 AngularJS 2 应用</h1>

插值表达式

插值表达式的语法格式为

{{ ... }}

插值表达式可以把计算的字符串插入 HTML 中,也可以作为属性值来使用

<h3>
  {{title}}
  <img src="{{imageUrl}}" style="height:30px">
</h3>

模板表达式

其实 {{ ... }} 里头就是一个模板表达式,AngularJS 会对其进行求值并转化为字符串输出

比如下面的代码将两个数相加

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

下面的代码使用 getVal() 获取表达式的值

<div class="example">
<div class="example_code">
[mycode3 type="html"]
<!-- "4" -->
<p>{{1 + 1 + getVal()}}</p>

AngularJS 模板表达式类似 JavaScript 的语言

很多 JavaScript 表达式也是合法的模板表达式,但不是全部

下面的 JavaScript 表达式是禁止的

  1. 赋值表达式(=,+=,-=...)
  2. new 操作符
  3. 带有;或者'的连接表达式
  4. 自增和自减操作( ++ 和 -- )

其它与 Javascript 语法不同的值得注意的包括

  1. 不支持位运算符( | 和 & )
  2. 模板表达式的操作符,如 | 和 ?. 等,被赋予了新的含义

属性绑定

模板的属性绑定可以把视图元素的属性设置为模板表达式

最常用的属性绑定是把元素的属性设置为组件中属性的值

  1. 将 image 元素的 src 属性会被绑定到组件的 imageUrl 属性上

    <img [src]="imageUrl">
    
  2. 当组件为 isUnchanged( 未改变 ) 时禁用一个按钮

    <button [disabled]="isUnchanged">按钮是禁用的</button>
    
  3. 设置指令的属性

    <div [ngClass]="classes"> [ngClass]绑定到 classes 属性</div>
    
  4. 设置一个自定义组件的属性,父子组件间通讯的重要途径

    <user-detail [user]="currentUser"></user-detail>
    

HTML 属性(Attribute)、 class 和 style 绑定

单向数据绑定适可以用于那些不太适合使用属性绑定的场景

属性(Attribute)、绑定

当元素没有属性可绑的时候,使用 HTML 标签属性(Attribute)绑定

考虑 ARIA, SVG 和 table 中的 colspan/rowspan 等属性(Attribute)

它们是纯粹的属性,没有对应的属性可供绑定,比如下面的代码会报错

<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>

我们会得到这个错误

Template parse errors:
Can't bind to 'colspan' since it isn't a known native property
模板解析错误:不能绑定到'colspan',因为它不是已知的原生属性

因为 <td> 元素没有 colspan 属性

但是插值表达式和属性绑定只能设置 属性 ,而不是 Attribute,所以需 HTML 标签 Attribute 绑定来创建和绑定类似的 Attribute

HTML 标签特性绑定在语法上类似于属性绑定,但中括号中的部分不是一个元素的属性名,而是由一个 attr. 的前缀和 HTML 标签属性的名称组成,然后通过一个能求值为字符串的表达式来设置 HTML 标签属性的值

<table border=1>
  <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
  <tr><td>Five</td><td>Six</td></tr>
</table>

css 类绑定

CSS 类绑定可以从元素的 class 属性上添加和移除 CSS 类名

CSS 类绑定在语法上类似于属性绑定,但方括号中的部分不是一个元素的属性名,而是包括一个 class 前缀,紧跟着一个点 (.) ,再跟着 CSS 类的名字组成

其中后两部分是可选的,比如: [class.class-name]

下面我们就来看看如何通过 CSS 类绑定类添加和移除 "special" 类

  1. 标准 HTML 样式类设置

    <div class="bad curly special">Bad curly special</div>
    
  2. 通过绑定重设或覆盖样式类

    <div class="bad curly special" [class]="badCurly">Bad curly</div>
    
  3. 通过一个属性值来添加或移除 special 样式类

    <div [class.special]="isSpecial">这个样式比较特殊</div>
    

style 样式绑定

通过样式绑定,可以设置内联样式

样式绑定语法上类似于属性绑定,但中括号里面的部分不是一个元素的属性名,样式绑定包括一个 style. ,紧跟着 CSS 样式的属性名

例如 [style.style-property]

<button [style.color] = "isSpecial ? 'red': 'green'">红色</button>
<button [style.background-color]="canSave ? 'cyan': 'grey'" >保存</button>

带有单位的样式绑定

<button [style.font-size.em]="isSpecial ? 3 : 1" >大</button>
<button [style.font-size.%]="!isSpecial ? 150 : 50" >小</button>

样式属性可以是中线命名法( font-size ),也可以是驼峰是命名法 ( fontSize )

事件绑定

AngularJS 通过监听用户动作,比如键盘事件、鼠标事件、触屏事件等来响应相对应的数据流向-从视图目标到数据源

语法

事件绑定的语法是由等号左侧小括号内的 目标事件 和右侧引号中的 模板声明 组成

比如下面的代码是事件绑定监听按钮的点击事件

只要点击鼠标,都会调用组件的 onSave() 方法

<button (click)="onSave()">保存</button>

圆括号中的名称,比如 (click) 标记出了目标事件

下面的代码,事件绑定的目标按钮的 click 事件

<button (click)="onSave()">Save</button>

也可以使用 on- 前缀的形式

<button on-click="onSave()">On Save</button>

使用 NgModel 进行双向数据绑定

当开发数据输入表单时,期望的结果是既能将组件的数据显示到表单上,也能在用户修改时更新组件的数据

下面的代码通过 [(NgModel)] 来实现双向绑定

<input [(ngModel)]="currentUser.firstName">

[] 实现了数据流从组件到模板

() 实现了数据流从模板到组件

两者一结合 [()]就实现了双向绑定

使用前缀形式的语法

<input bindon-ngModel="currentUser.firstName">

内置指令

Angular 的内置指令有

  1. NgClass
  2. NgStyle
  3. NgIf
  4. NgFor
  5. NgSwitch

NgClass

通过绑定到 NgClass 动态添加或删除 CSS 类

<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" >这个div是大号的</div>

NgStyle

NgStyle 通过绑定到 key:value 控制对象的形式,可以同时设置多个内联样式

setStyles() {
  let styles = {
    // CSS属性名
    'font-style':  this.canSave      ? 'italic' : 'normal',  // italic
    'font-weight': !this.isUnchanged ? 'bold'   : 'normal',  // normal
    'font-size':   this.isSpecial    ? '24px'   : '8px',     // 24px
  };
  return styles;
}

通过添加一个 NgStyle 属性绑定,调用 setStyles 并据此来设置元素的样式

<div [ngStyle]="setStyles()">
这个 div 的样式是 italic, normal weight, 和extra large (24px)
</div>

*ngIf

将 NgIf 指令绑定到一个真值表达式,可以把一个元素及其子元素添加到 dom

<div *ngIf="currentUser">Hello,{{currentUser.firstName}}</div>

相反,绑定到一个假值表达式将从 DOM 中移除该元素及其子元素

<!-- 因为 isActive 的值为 false,所以 user-detail 不在 DOM 中-->
<user-detail *ngIf="isActive"></user-detail>

NgSwitch

NgSwitch 用于从一组可能的元素树中根据条件显示其中一个

AngularJS NgSwitch 只把选中的元素添加进 DOM 中

<span [ngSwitch]="userName">
  <span *ngSwitchCase="'张三'">张三</span>
  <span *ngSwitchCase="'李四'">李四</span>
  <span *ngSwitchCase="'王五'">王五</span>
  <span *ngSwitchCase="'赵六'">赵六</span>
  <span *ngSwitchDefault>龙大</span>
</span>

上面的代码把作为父指令的 NgSwitch 绑定到一个能返回开关值的表达式

代码中的这个值是字符串,但它可以是任何类型的值

父指令 NgSwitch 控制一组 <span> 子元素

每个 <span> 或者挂在一个匹配值的表达式上,或者被标记为默认情况

任何时候,这些 span 中最多只有一个会出现在 DOM 中

如果这个 span 的匹配值和开关值相等,Angular2 就把这个 <span> 添加DOM中

如果没有任何 span 匹配上,Angular2 就会把默认的 span 添加到DOM中

Angular2 会移除并销毁所有其它的 span

三个相互合作的指令

  1. ngSwitch:绑定到一个返回开关值的表达式
  2. *ngSwitchCase:绑定到一个返回匹配值的表达式
  3. *ngSwitchDefault:一个用于标记默认元素的属性
不要在 ngSwitch 前使用 * ,而应该用属性绑定,但 ngSwitchCase 和 ngSwitchDefault 前面要放 *

*ngFor

*NgFor 用于展示一个由多个条目组成的列表

下面的代码在一个 HTML 块上应用 NgFor

<div *ngFor="let user of users">{{user.fullName}}</div>

*ngFor 也可以用在一个组件元素上

<user-detail *ngFor="let user of users" [user]="user"></user-detail>

*ngFor 指令支持一个可选的 index 索引,在迭代过程中会从 0 增长到数组中的长度

可以通过模板输入变量来捕获这个 index,并应用在模板中

下面的代码把 index 捕获到了一个名为 i 的变量中

<div *ngFor="let user of users; let i=index">{{i + 1}} - {{user.fullName}}</div>

*ngFor - trackBy

*ngFor 指令有时候会性能较差,特别是在大型列表中

对一个条目的一点小更改、移除或添加,都会导致级联的 DOM 操作

比如,当通过重新从服务器来刷新通讯录,刷新后的列表可能包含很多(如果不是全部的话)以前显示过的联系人

但在 Angular 看来,它不知道哪些是以前就存在过的,只能清理旧列表、舍弃那些 DOM 元素,并用新的 DOM 元素来重建一个新列表

为了解决这个问题,可以通过追踪函数来避免这种折腾

追踪函数会告诉 Angular 我们知道两个具有相同 user.id 的对象是同一个联系人

trackByUsers(index: number, user: User){return user.id}

然后,把 *ngFor - TrackBy 指令设置为那个追踪函数

<div *ngFor="let user of users; trackBy:trackByUsers">({{user.id}}) {{user.fullName}}</div>

追踪函数不会排除所有 DOM 更改

如果用来判断是否为同一个联系人的属性变化了,就会更新 DOM 元素,反之就会留下这个 DOM 元素

列表界面就会变得比较更加平滑,具有更好的响应效果

模板引用变量

模板引用变量是模板中对 DOM 元素或指令的引用

它能在原生 DOM 元素中使用,也能用于 Angular 组件——实际上,它可以和任何自定义 Web 组件协同工作

我们可以在同一元素、兄弟元素或任何子元素中引用模板引用变量

<!-- phone 引用了 input 元素,并将 `value` 传递给事件句柄 -->
<input #phone placeholder="phone number">
<button (click)="callPhone(phone.value)">Call</button>
<!-- fax 引用了 input 元素,并将  `value` 传递给事件句柄  -->
<input ref-fax placeholder="fax number">
<button (click)="callFax(fax.value)">Fax</button>

"phone" 的 (#) 前缀意味着我们将要定义一个 phone 变量

链接: https://fly63.com/course/15_848