Angular 2 ngFor vs Angular 1 ng-repeat

一直想写关于 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: `
    
Grocery selected: {{ $ctrl.selectedGrocery.label }}
`, ... };

Using $index and track by

$index 表示数组中每一项的索引值,除了 $index 之外,ng-repeat 还导出$first$last$even$odd 等属性,详细信息可以查看 - ngRepeat官方文档。接下来,我们先来看一下 $index 示例:

const app = {
  template: `
    ...
        
  • {{ grocery.label }} {{ $index }}
  • ... `, ... };

    在设置 ng-repeat 初始数据时,你可能已经注意到了, this.groceries 数组中的每一项都有一个唯一的 id 属性,基于这个唯一的属性,我们可以通过 ng-repeat 指令提供的 track by 表达式,进行页面性能优化,防止 Angular 重新渲染整个列表。即不是每次销毁和重建列表相关的 DOM 树,而是重新渲染那些需要更新的 DOM 元素。

    const app = {
      template: `
        ...
            
  • {{ grocery.label }} {{ $index }}
  • ... `, ... };

    此外 track by 也支持函数表达式:

    const app = {
      template: `
        ...
            
  • {{ grocery.label }} {{ $index }}
  • ... `, ... };

    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: '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'
        }];
        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: `
        
    Grocery selected: {{ selectedGrocery.label }}
    ` }) export class AppComponent { public groceries: Grocery[]; public selectedGrocery: Grocery; constructor() { 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' }]; this.selectGrocery(this.groceries[0]); } selectGrocery(grocery: Grocery) { this.selectedGrocery = grocery; } }

    细心的读者,可能会注意到模板中 *ngFor 语法,ngFor 指令前面的 * 号是语法糖,表示使用