一直想写关于 Angular 1.x 与 Angular 2.x (Angular 4.x 已发布) 区别的文章,方便 Angular 1.x 的用户快速的过渡到 Angular 2.x。在浏览文章的时候,发现 Todd Motto 大神,已经写了相关的系列文章。英文好的同学,建议直接阅读 From ng-repeat in Angular 1.x to ngFor in Angular 2 原文哈,因为我并不打算完整地翻译。废话不多说,接下来我们开始进入正题。
目录
-
Angular 1.x
Using ng-repeat
Using $index and track by
-
Angular 2.x
Using ngFor
Using index and trackBy
Angular 1.x
Using ng-repeat
在使用 ng-repeat 指令之前,我们需要组件相关的控制器中设置添加初始数据,具体如下:
const app = {
controller() {
this.groceries = [{
id: 0,label: 'Butter'
},{
id: 1,label: 'Apples'
},{
id: 2,label: 'Paprika'
},{
id: 3,label: 'Potatoes'
},{
id: 4,label: 'Oatmeal'
},{
id: 5,label: 'Spaghetti'
},{
id: 6,label: 'Pears'
},{
id: 7,label: 'Bacon'
}];
}
};
angular
.module('app')
.component('app',app);
接下来我们在组件模板中,使用 ng-repeat 指令显示我们上面定义的数据:
const app = {
template: `
<div>
Grocery selected: {{ $ctrl.selectedGrocery.label }}
<ul>
<li ng-repeat="grocery in $ctrl.groceries">
<a href="" ng-click="$ctrl.selectGrocery(grocery);">
{{ grocery.label }}
</a>
</li>
</ul>
</div>
`,...
};
Using $index and track by
$index 表示数组中每一项的索引值,除了 $index 之外,ng-repeat 还导出$first、$last、$even 和 $odd 等属性,详细信息可以查看 - ngRepeat官方文档。接下来,我们先来看一下 $index 示例:
const app = {
template: `
...
<li ng-repeat="grocery in $ctrl.groceries">
<a href="" ng-click="$ctrl.selectGrocery(grocery);">
{{ grocery.label }} {{ $index }}
</a>
</li>
...
`,...
};
在设置 ng-repeat 初始数据时,你可能已经注意到了, this.groceries 数组中的每一项都有一个唯一的 id 属性,基于这个唯一的属性,我们可以通过 ng-repeat 指令提供的 track by 表达式,进行页面性能优化,防止 Angular 重新渲染整个列表。即不是每次销毁和重建列表相关的 DOM 树,而是重新渲染那些需要更新的 DOM 元素。
const app = {
template: `
...
<li ng-repeat="grocery in $ctrl.groceries track by grocery.id">
<a href="" ng-click="$ctrl.selectGrocery(grocery);">
{{ grocery.label }} {{ $index }}
</a>
</li>
...
`,...
};
此外 track by 也支持函数表达式:
const app = {
template: `
...
<li ng-repeat="grocery in $ctrl.groceries track by trackByGrocery(grocery)">
<a href="" ng-click="$ctrl.selectGrocery(grocery);">
{{ grocery.label }} {{ $index }}
</a>
</li>
...
`,...
};
Angular 2.x
Angular 2.x 中不存在 ng-repeat 指令,取而代之的是 ngFor 指令。它们的语法非常相似,但需要注意的一点在遍历集合是,Angular 2 使用 of 代替了 in 。
Using ngFor
interface Grocery {
id: number;
label: string;
}
export default class AppComponent {
public groceries: Grocery[];
public selectedGrocery: Grocery;
constructor() {
this.groceries = [{
id: 0,label: 'Bacon'
}];
this.selectGrocery(this.groceries[0]);
}
selectGrocery(grocery: Grocery) {
this.selectedGrocery = grocery;
}
}
设置好初始化数据,接下来我们来使用 ngFor 指令,需要注意的是在模板中,我们需要使用 let 关键字创建局部作用域,具体示例如下:
import { Component } from '@angular/core';
interface Grocery {
id: number;
label: string;
}
@Component({
selector: 'exe-app',template: `
<div>
Grocery selected: {{ selectedGrocery.label }}
<ul>
<li *ngFor="let grocery of groceries;">
<a href="#" (click)="selectGrocery(grocery);">
{{ grocery.label }}
</a>
</li>
</ul>
</div>
`
})
export class AppComponent {
public groceries: Grocery[];
public selectedGrocery: Grocery;
constructor() {
this.groceries = [{
id: 0,label: 'Bacon'
}];
this.selectGrocery(this.groceries[0]);
}
selectGrocery(grocery: Grocery) {
this.selectedGrocery = grocery;
}
}
细心的读者,可能会注意到模板中 *ngFor 语法,ngFor 指令前面的 * 号是语法糖,表示使用 <template> 元素。详细内容,我们会在 "我有话说" 章节介绍。
Using index and trackBy
在 Angular 1.x 中我们可以直接 $index 访问到列表项的索引值,但在 Angular 2 中,我们使用 index 之前,我们必须先把它赋值给其它变量,具体示例如下:
@Component({
selector: 'exe-app',template: `
<div>
Grocery selected: {{ selectedGrocery.label }}
<ul>
<li *ngFor="let grocery of groceries; let i = index;">
<a href="#" (click)="selectGrocery(grocery);">
{{ grocery.label }} {{ i }}
</a>
</li>
</ul>
</div>
`
})
export default class AppComponent {...}
介绍完 ngFor 中的 index 用法,接下来我们来看一下 trackBy 用法。在 Angular 2 中不支持 Angular 1.x 中的 track by x 如:track by grocery.id 语法, trackBy 只支持函数。我们来看一下具体示例:
@Component({
selector: 'exe-app',template: `
<div>
Grocery selected: {{ selectedGrocery.label }}
<ul>
<li *ngFor="let grocery of groceries; let i = index; trackBy: trackByGrocery;">
<a href="#" (click)="selectGrocery(grocery);">
{{ grocery.label }} {{ i }}
</a>
</li>
</ul>
</div>
`
})
export default class AppComponent {
...
trackByGrocery: (index: number,grocery: Grocery): number => grocery.id;
...
}
完整示例如下:
import { Component } from '@angular/core';
interface Grocery {
id: number;
label: string;
}
@Component({
selector: 'exe-app',template: `
<div>
Grocery selected: {{ selectedGrocery.label }}
<ul>
<li *ngFor="let grocery of groceries; let i = index; trackBy: trackByGrocery;">
<a href="#" (click)="selectGrocery(grocery);">
{{ grocery.label }} {{ i }}
</a>
</li>
</ul>
</div>
`
})
export class AppComponent {
public groceries: Grocery[];
public selectedGrocery: Grocery;
constructor() {
this.groceries = [{
id: 0,label: 'Bacon'
}];
this.selectGrocery(this.groceries[0]);
}
selectGrocery(grocery: Grocery) {
this.selectedGrocery = grocery;
}
trackByGrocery(index: number,grocery: Grocery): number {
return grocery.id
}
}
我有话说
1.Angular 2 指令有几种分类?
在 Angular 2 指令分为三类:
组件(Component directive):用于构建UI组件,继承于 Directive 类
属性指令(Attribute directive): 用于改变组件的外观或行为
结构指令(Structural directive): 用于动态添加或删除DOM元素来改变DOM布局
详细内容请参考 - Angular 2 Directive
2.Angular 2 中的模板语法有哪一些?
Angular 2 中没有 Angular 1.x ng-click 、ng-bind、ng-show 等指令,取而代之的是新的模板语法。
2.1 属性绑定:
<show-title [title]="title"></show-title>
2.2 事件绑定:
<a href="#" (click)="selectGrocery(grocery);">
{{ grocery.label }} {{ i }}
</a>
详细内容请参考 - Angular 2 template syntax & common directives