Angular 17+ 全新迭代语法@for

有关新 @for 模板语法的所有功能和最佳实践,以及对现在强制的跟踪功能的解释。


随着 Angular 17 的发布,新的控制流语法(包括该@for语法)为开发人员带来了更好的体验。

以前,我们需要从@angular/common 导入ngFor指令在 Angular 模板中迭代数组。

但现在,@for内置模板语法简化了模板迭代,为开发人员提供了更直观的循环机制。

它提供了更简洁、性能更安全的体验ngFor,而无需任何额外的导入。


@for中的track

跟踪函数track用于使 Angular 变化检测机制能够准确地知道在输入数组发生变化后需要在 DOM 中更新哪些项目。跟踪功能告诉 Angular 如何唯一地标识列表中的元素。熟悉vue和react的同学对此并不陌生。这不就是用来diff算法优化的吗。

typescript 复制代码
@Component({
  template: `<ul>
    @for (fruit of fruits; track fruit.id) {
    <li>{{ fruit }}</li>
    }
  </ul>`,
})
class CoursesComponent {
  fruits = [
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 3, name: "Orange" },
  ];
}

这里我们使用id作为唯一标识传给track。当然我们还可以给track传函数

typescript 复制代码
@Component({
  template: `<ul>
    @for (fruit of fruits; track trackFruit) {
    <li>{{ fruit }}</li>
    }
  </ul>`,
})
class CoursesComponent {
  fruits = [
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 3, name: "Orange" },
  ];
  trackFruit(index: number, fruit: Fruit) {
    return fruit.id;
  }
}

可以更灵活的自定义track函数。

@for 与 @empty

在没有@for之前,当迭代数组为空的时候我们需要展示一些提示信息,这是一个很常见的功能。

typescript 复制代码
@Component({
  template: `
    <ul>
      <ng-container *ngFor="let item of items">
        <li>{{ item }}</li>
      </ng-container>
      <ng-container *ngIf="items.length === 0">
        <li>No Data</li>
      </ng-container>
    </ul>
  `,
  standalone: true,
  imports:[NgForOf, NgIf]
})
class Example {
  items = [];
}

我们还需要用到ngIf做单独的判断。但是有了@for以后我们可以这样写

typescript 复制代码
@Component({
  template: `<ul>
    @for (item of items; track item) {
    <li>{{ item }}</li>
    }
    @empty {
    <li>No Data</li>
    }
  </ul>`,
})
class Example {
  items = [];
}

可以看到新的写法更简洁,代码结构更清晰。

@for 与 可迭代对象

@for不知支持数组的迭代,而是所有的可迭代对象。以下是一个map的例子

typescript 复制代码
@Component({
  template: `<ul>
    @for (entry of map; track entry) {
    <li>{{ entry[0] }}: {{ entry[1] }}</li>
    }
  </ul>`,
})
class Example {
  map = new Map([
    ["firstName", "Apple"],
    ["lastName", "Banana"],
  ]);
}

我们甚至可以直接遍历一个字符串,因为它也是可迭代的。

@for控制流中的隐式变量

$index用于记录当前遍历的索引值

typescript 复制代码
@Component({
  template: `<ul>
    @for (item of items; track item; let index = $index) {
    <li>{{ index }}: {{ item }}</li>
    }
  </ul>`,
})
class Example {
  items = ["Apple", "Banana", "Orange"];
}

$first保存一个布尔值,指示当前项是否是集合中的第一个项。
$last保存一个布尔值,指示当前项目是否是集合中的最后一项。

typescript 复制代码
@Component({
  template: `
    <ul>
      @for (item of items; track item; let first = $first, last = $last) {
      <li>{{ item }}: {{ first }}: {{ last }}</li>
      }
    </ul>
  `
})
class Example {
  items = ["Apple", "Banana", "Orange"];
}

//Apple: true: false
//Banana: false: false
//Orange: false: true

$odd保存一个布尔值,指示当前索引是否为奇数:1、3、5...
$even保存一个布尔值,指示当前索引是否为偶数:0、2、4...
$count记录了正在循环的 Iterable 元素的总数
用法与上述相同不过多展示了。

使用 Angular CLI 迁移到 @for

git bash 复制代码
ng generate @angular/core:control-flow