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 原文哈,由於我並不打算完整地翻譯。廢話很少說,接下來咱們開始進入正題。javascript

目錄

  • Angular 1.xhtml

    • Using ng-repeatjava

    • Using $index and track byangularjs

  • Angular 2.xweb

    • Using ngFortypescript

    • Using index and trackBysegmentfault

Angular 1.x

Using ng-repeat

在使用 ng-repeat 指令以前,咱們須要組件相關的控制器中設置添加初始數據,具體以下:api

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: '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: `
    <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: '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 指令前面的 * 號是語法糖,表示使用 <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: '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;
  }

  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-clickng-bindng-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

相關文章
相關標籤/搜索