Angular 2 ngFor vs Angular 1 ng-repeat

分類:IT技術 時間:2017-04-04

一直想寫關於 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: '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="https://segmentfault.com/a/#" (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="https://segmentfault.com/a/#" (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="https://segmentfault.com/a/#" (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="https://segmentfault.com/a/#" (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="https://segmentfault.com/a/#" (click)="selectGrocery(grocery);">
    {{ grocery.label }} {{ i }}
</a>

詳細內容請參考 - Angular 2 template syntax & common directives


Tags: selected 控制器 英文 文章 用戶

文章來源:


ads
ads

相關文章
ads

相關文章

ad