Angular 中的一个新 RFC,“内置控制流”让我(和许多其他人)兴奋,但不是每个人。有些人不喜欢变化本身,有些人不喜欢结构指令将被弃用,有些人不喜欢新语法的外观,等等。在这里我将解释为什么我喜欢这个新想法。
结构指令不应该是指令
它们与应用它们的组件无关。
看看这段代码:
<ul>
<li *ngFor="let item of items">
{{item.label}}
</li>
</ul>
这ngFor
不是渲染元素的属性li
- 它定义了该元素是否应该被渲染。
现在让我们的代码稍微复杂一点,只渲染具有非空标签的项目:
<ul>
<ng-container *ngFor="let item of items">
<li *ngIf="!!item.label">
{{item.label}}
</li>
</ng-container>
</ul>
因为我们不能对一个元素应用多个结构指令,所以我们离开ngFor
了li
,它不会影响li
外观或行为。
如果我们可以将它移出,那么它就不是 的“属性” li
,而是一种控制流机制,作为指令实现——在第二个示例中,它仍然是一个指令,应用于人工元素ng-container
。它应该作为一种控制流机制来实现,而不应该看起来像某个元素的属性。
它使代码更紧凑
即使是 Angular 模板中简单的“if-else”现在看起来也很尴尬。像“if-else if-else”这样的情况很快就会变得令人困惑并且太大了:
<ng-container *ngIf="item.type==='email'; else nonEmail">
<a href="mailto:{{item.ref}}">{{item.ref}}</a>
</ng-container>
<ng-template #nonEmail>
<ng-container *ngIf="!!item.label; else noLabel">
<a href="{{item.ref}}">{{item.label}}</a>
</ng-container>
<ng-template #noLabel>
<div>Wrong link</div>
</ng-template>
</ng-template>
比较它:
{#if item.type==='email'}
<a href="mailto:{{item.ref}}">{{item.ref}}</a>
{:elseif !!item.label }
<a href="{{item.ref}}">{{item.label}}</a>
{:else}
<div>Wrong link</div>
{/if}
比用户态指令更强大
由于新控制流的“内置”特性,框架可以在“构建”阶段进行一些“准备”和优化。它为以前不可能(或实施起来非常棘手)的事情打开了大门。一个很好的例子是#defer
(参见“ RFC:延迟加载”)。
删除微语法限制
我们将获得更好的类型检查和类型缩小。
如果你还没有听说过微语法:每次你写
<li *ngFor="let item of items; index as i; trackBy: trackByFn">{{item}}</li>
Angular 将其翻译成长格式ngFor
(我敢肯定,很少有开发人员定期使用):
<ng-template ngFor
let-item
[ngForOf]="items"
let-i="index"
[ngForTrackBy]="trackByFn"
>
<li>{{item}}</li>
</ng-template>
因此,开发人员必须创建微语法以使这种速记成为可能,以免让您使用带有笨拙 API 的长格式。内置的控制流消除了这种尴尬并提供了更好的类型缩小。
第三方结构指令将保留
有众所周知且非常方便的结构指令,如rxFor、ngrxLet ——它们不会被弃用或以任何方式受到影响。结构指令本身的概念不会被弃用:您仍然可以创建和使用它们。他们无法获得内置控制流所具有的所有功能,但他们现有的功能也无济于事。
我理解 Angular 团队为什么他们不想让新的控制流语法可扩展的原因——一旦他们提供 API,他们就会受到给定 API 的限制。这样的 API 有机会对第三方指令有益,但框架的这种定义特性的不受阻碍的发展更为重要。
这是一个大大改进 Angular 的机会
控制流是一个必不可少的特性,是框架的核心特性之一。这方面的任何改进都将对每个开发人员都极为有益。
内置控制流从“用户态代码”中移除了控制流,并赋予了框架完全控制权——它不再只是一些结构指令,因此 Angular 可以以更优化的方式做更多的事情。