Angular 18 中的新功能

2025-05-28

Angular 18 中的新功能

介绍

2024 年 5 月 22 日星期三,Angular 核心团队发布 Angular 的新版本:版本 18。

此版本不仅稳定了最新的 API,还引入了许多旨在简化框架使用和改善开发人员体验的新功能。

这些新功能是什么?继续阅读,一探究竟。

新的控制流语法现已稳定

Angular 最新版本发布时,引入了一种管理视图流的新方法。需要提醒的是,这种新的控制流直接集成到了 Angular 模板编译器中,使得以下结构型指令成为可选的:

  • ngIf
  • ngFor
  • ngSwitch / ngSwitchCase
<!-- old way -->
<div *ngIf="user">{{ user.name }}</div>

<!-- new way -->
@if(user) {
  <div>{{ user.name }}</div>
}
Enter fullscreen mode Exit fullscreen mode

这个新的 API 现在已经稳定,我们建议使用这个新语法。

如果您想将您的应用程序迁移到这个新的控制流,可以使用示意图。

ng g @angular/core:control-flow
Enter fullscreen mode Exit fullscreen mode

此外,新的@for语法取代了 ngFor 指令,迫使我们使用 track 选项来优化列表的渲染并避免在更改期间完全重新创建它们。

开发模式中增加了两个新的警告:

  • 如果跟踪键重复,则会发出警告。如果所选键值在您的集合中不唯一,则会发出此警告。

  • 如果跟踪键是整个项目,并且选择此键会导致整个列表被销毁并重新创建,则会发出警告。如果操作成本过高(但门槛较低),则会显示此警告。

Defer 语法现在稳定了

@defer语法也是在 Angular 的最新版本中引入的,它允许你定义一个块,当满足某个条件时,该块会被延迟加载。当然,此块中使用的任何第三方指令、管道或库也将被延迟加载。

以下是其使用示例


@defer(when user.name === 'Angular') {
  <app-angular-details />
}@placeholder {
  <div>displayed until user.name is not equal to Angular</div>
}@loading(after: 100ms; minimum 1s) {
  <app-loader />
}@error {
  <app-error />
}
Enter fullscreen mode Exit fullscreen mode

提醒一下,

Zone.js 将会怎样

Angular 18 引入了一种触发检测变更的新方法。之前,检测变更完全由 Zone.js 处理,这并不令人意外。现在,检测变更将由框架本身直接触发。

为了实现这一点,框架中新增了一个新的变更检测调度器 ( ChangeDetectionScheduler ),该调度器将在内部用于触发变更检测。这个新的调度器不再基于 Zone.js,而是在 Angular 18 版本中默认使用。

如果发生以下情况,新的调度程序将引发检测变化

  • 触发模板或主机监听事件
  • 视图被附加或删除
  • 异步管道接收新值
  • markForCheck 函数被调用
  • 信号值发生变化等。

小文化时刻:这种检测变化是由于内部调用了ApplicationRef.tick函数。

正如我上面提到的,由于 18 版 Angular 已经基于这个新的调度程序,因此当您迁移应用程序时,不会发生任何中断,因为 Angular 可能会收到 Zone Js 和/或这个新调度程序的检测更改通知。

但是,要恢复到 Angular 18 之前的行为,您可以使用 provideZoneChangeDetection 函数并将ignoreChangesOutsideZone setter 选项设置为 true。

bootstrapApplication(AppComponent, {
  providers: [
    provideZoneChangeDetection({ ignoreChangesOutsideZone: true })
  ]
});
Enter fullscreen mode Exit fullscreen mode

此外,如果您希望仅依赖新的调度程序而不依赖 Zone Js,则可以使用provideExperimentalZonelessChangeDetection函数。

bootstrapApplication(AppComponent, {
  providers: [
    provideExperimentalZonelessChangeDetection()
  ]
});
Enter fullscreen mode Exit fullscreen mode

通过实现provideExperimentalZonelessChangeDetection函数,Angular 不再依赖于 ZoneJs,这使得

  • 如果项目的其他依赖项都不依赖 Zone js,则删除 Zone js 依赖项
  • 从 angular.json 文件中的 polifills 中删除 zone js

HttpClientModule 的弃用

自从 Angular 14 版和独立组件的出现以来,模块在 Angular 中已成为可选项,现在是时候看到第一个被弃用的模块了:我将 HttpClientModule 命名为

该模块负责为整个应用程序注册 HttpClient 单例,以及注册拦截器。

该模块可以轻松地由provideHttpClient函数替换,并具有支持 XSRF 和 JSONP 的选项。

此函数有一个用于测试的孪生姐妹:provideHttpClientTesting

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient()
  ]
});
Enter fullscreen mode Exit fullscreen mode

与往常一样,Angular 团队提供了示意图来帮助您迁移应用程序。

当发出ng update @angular/core @angular /cli命令时,如果在应用程序中使用 HttpClientModule,则会发出迁移请求

ng-content 回退

ng-content 是 Angular 中的一个重要特性,尤其是在设计通用组件时。

此标签允许您投射您自己的内容。但是,此功能有一个主要缺陷。您无法为其指定默认内容。

从版本 18 开始,情况不再如此。您可以将内容放在如果开发人员未提供任何内容,则会显示该标签。

我们以按钮组件为例

<button>
  <ng-content select=".icon">
   <i aria-hidden="true" class="material-icons">send</i>
  </ng-content>
  <ng-content></ng-content>
</button> 
Enter fullscreen mode Exit fullscreen mode

使用按钮组件时,如果没有提供带有图标类的元素,则会显示图标发送

表单事件:对表单事件进行分组的方式

这是社区很久以前提出的一个请求:有一个 API 可以将表单中可能发生的事件分组;当我说事件时,我指的是以下事件

  • 原始的
  • 感动
  • 状态改变
  • 重置
  • 提交

Angular 18 版本从 AbstractControl 类中公开了一个新的事件属性(允许 FormControl、FormGroup 和 FormArray 继承此属性),该属性返回一个可观察的

@Component()
export class AppComponent {
  login = new FormControl<string | null>(null);

  constructor() {
   this.login.events.subscribe(event => {
    if (event instanceof TouchedChangeEvent) {
        console.log(event.touched);
      } else if (event instanceof PristineChangeEvent) {
        console.log(event.pristine);
      } else if (event instanceof StatusChangeEvent) {
        console.log(event.status);
      } else if (event instanceof ValueChangeEvent) {
        console.log(event.value);
      } else if (event instanceof FormResetEvent) {
        console.log('Reset');
      } else if (event instanceof FormSubmitEvent) {
        console.log('Submit');
      }
   })
  }
}
Enter fullscreen mode Exit fullscreen mode

路由:重定向作为函数

在 Angular 的最新版本之前,当你想要重定向到另一个路径时,你需要使用redirectTo属性。该属性的值只能是一个字符串

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMath: 'full' },
  { path: 'home', component: HomeComponent }
];
Enter fullscreen mode Exit fullscreen mode

现在可以使用此属性传递一个函数。该函数接受ActivatedRouteSnapshot作为参数,允许您从 URL 中检索 queryParams 或 params。
另一个有趣的点是,此函数在注入上下文中调用,从而可以注入服务。

const routes: Routes = [
  { path: '', redirectTo: (data: ActivatedRouteSnapshot) => {
    const queryParams = data.queryParams
    if(querParams.get('mode') === 'legacy') {
      const urlTree = router.parseUrl('/home-legacy');
      urlTree.queryParams = queryParams;
      return urlTree;
    }
    return '/home';
  }, pathMath: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'home-legacy', component: HomeLegacyComponent }
];
Enter fullscreen mode Exit fullscreen mode

服务器端渲染:两个很棒的新功能

Angular 18 引入了两个重要且备受期待的新服务器端渲染功能

  • 事件重播
  • 国际化

重播事件

当我们创建一个服务器端渲染应用程序时,该应用程序会以 HTML 格式发送回浏览器,显示一个静态页面,然后由于 hydration 现象,该页面会变为动态页面。在此 hydration 阶段,无法发送任何交互响应,因此用户交互会丢失,直到 hydration 完成。

Angular 能够记录此水化阶段的用户交互,并在应用程序完全加载并可交互后重播它们。

要解锁此功能,仍在开发人员预览中,您可以使用 ServerSideFeature withReplayEvents函数。

providers: [
  provideClientHydration(withReplayEvents())
]
Enter fullscreen mode Exit fullscreen mode

国际化

随着 Angular 16 的发布,Angular 改变了页面数据同步的方式。破坏性数据同步已被渐进式数据同步所取代。然而,当时缺少一项重要功能:国际化支持。Angular 跳过了标记为 i18n 的元素。

新版本中不再存在这种情况。请注意,此功能仍处于开发预览阶段,可以使用withI18nSupport函数激活。

providers: [
  provideClientHydration(withI18nSupport())
]
Enter fullscreen mode Exit fullscreen mode

国际化

Angular 建议对于与 Angular 应用程序国际化有关的所有事宜使用 INTL 原生 javascript API。

根据此建议, @angular/common包暴露的函数助手已被弃用。因此,例如 getLocaleDateFormat 之类的函数不再被推荐使用。

新的构建器包和弃用

到目前为止,自从 vite 出现在 Angular 中以来,用于构建 Angular 应用程序的构建器都在包中:@angular-devkit/build-angular

这个软件包包含 Vite、Webpack 和 Esbuild。对于未来只使用 Vite 和 Esbuild 的应用程序来说,这个软件包太重了。

考虑到这个潜在的未来,我们创建了一个仅包含 Vite 和 Esbuild 的新包,名称为@angular/build

迁移到 Angular 18 时,如果应用程序不依赖 Webpack(例如,没有基于 Karma 的单元测试),则可以运行一个可选的原理图。该原理图将修改 angular.json 文件以使用新的包,并通过添加新包并删除旧包来更新 package.json。

重要的是,旧包可以继续使用,因为它为新包提供了别名。

Angular 通过在项目的 node_modules 中添加必要的依赖项,开箱即用地支持 Less Sass Css 和 PostCss。

然而,随着新的@angular/build包的到来,Less 和 PostCss 变得可选,并且必须在 package.json 中明确作为开发依赖项。

当您迁移到 Angular 18 时,如果您希望使用新包,这些依赖项将自动添加。

不再需要向下层异步/等待

Zone.js 不支持 JavaScript 的async/await特性。
为了不限制开发者使用此功能,Angular 的 CLI 会将使用async/await 的代码转换为“常规”的 Promise。

这种转换称为降级,就像将 Es2017 代码转换为 Es2015 代码一样。

随着不再基于 Zone.js 的应用程序的出现,即使目前仍处于实验阶段,如果 Zone.js 不再在 polyfill 中声明,Angular 也不会降级。
因此,应用程序的构建将更快、更轻量。

新的别名:ng dev

从现在开始,当运行ng dev命令时,应用程序将以开发模式启动。

实际上,ng dev 命令是ng serve命令的别名。

创建此别名是为了与 Vite 生态系统保持一致,特别是 npm run dev 命令。

未来

Angular 团队再次发布了一个充满新功能的版本,这无疑将极大地增强开发人员的体验,并向我们展示 Angular 的未来一片光明。

我们对未来有何期待?

毫无疑问,性能和开发人员体验将继续得到改善。

我们还将看到基于信号的形式、基于信号的组件的引入,以及很快使用@let 块声明模板变量的能力。

文章来源:https://dev.to/this-is-angular/whatnew-in-angular-18-60j
PREV
更好的编码方式:文档驱动开发 API 很难 测试很难 直奔主题 完善流程 现在就把它带回来 结论
NEXT
Angular 在 2020 年举步维艰 Angular 团队陷入困境 Angular 生态系统正在分崩离析 大量未解决的问题和拉取请求 没有公开的路线图