Angular, v15 到 v17 的新功能重點整理
記得幾年前我接觸 Angular 時,當時的版本還是 v15 。如今 Angular 已經進入 v20 版本了!這些版本中有許多新功能,讓我們來快速回顧一下重點更新,當然若須深入了解,官方文件有各功能更詳細的介紹可參考。
由於內容稍多,所以將分為上下篇;此篇為上篇,介紹 v15 到 v17 的主要新功能。 ( v18 到 v20 請見下一篇)
Angular v15
Standalone Components 正式版
告別 NgModule,可以直接宣告元件(Component)、指令(Directive)、管道(Pipe)。
1
2
3
4
5
6
7
8import { Component } from '@angular/core';
({
standalone: true,
selector: 'app-hello',
template: `<h1>Hello Standalone!</h1>`,
})
export class HelloComponent {}
Directive Composition API
元件可直接複用多個指令的行為,這個功能僅適用於 standalone 指令。
在 v15 為實驗性功能,後續版本已進入穩定版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// 定義可複用的指令
({
standalone: true,
selector: '[hasColor]'
})
export class HasColor {
color: string = ''; ()
}
({
standalone: true,
selector: '[cdkMenu]'
})
export class CdkMenu {
cdkMenuDisabled: boolean = false; ()
new EventEmitter(); () cdkMenuClosed =
}
// 在元件中組合多個指令
({
selector: 'mat-menu',
standalone: true,
hostDirectives: [
HasColor,
{
directive: CdkMenu,
inputs: ['cdkMenuDisabled: disabled'],
outputs: ['cdkMenuClosed: closed']
}
],
template: `<div>Custom Menu</div>`
})
export class MatMenu {}
Angular v16
Signals
一種新的響應式狀態管理方式。
提供宣告式、可預測的資料流和變更偵測。
在 v16 為實驗性功能,後續版本已進入穩定版
官方詳細介紹: https://angular.dev/guide/signals
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import { signal, computed, effect } from '@angular/core';
interface User { name: string; age: number; }
export class CounterComponent {
// 建立 signal
user: WritableSignal<User> = signal<User>({ name: '小明', age: 16 });
// 直接對 signal 設定新值
setUser() {
this.user.set({ name: '小明', age: 24 });
}
// 透過 callback 對 signal 設定新值
updateUser() {
this.user.update(u => ({ ...u, age: u.age + 1 }));
}
// 透過 asReadonly 從來源取得唯讀的 signal
readonlyUser: Signal<User> = this.user.asReadonly();
// 來源signal變動時(且computed的signal被template使用),會呼叫callback
isAdult: Signal<boolean> = computed(() => this.user().age >= 18);
// 來源signal變動時,會呼叫callback
logEffect = effect(() => {
console.log('User changed:', this.user());
});
}
Input() 支援 required 關鍵字
可以直接在裝飾器 @Input() 加上 required
來強制要求父元件一定要傳入這個 input 屬性。這樣如果父元件沒有提供這個 input,開發時就會出現錯誤。
(基於裝飾器的 @InputAPI 仍可使用,不過官方在之後的版本,建議在新專案中使用基於 signal 的 input。)
1 | required: true }) name1: string = ''; ({ |
SSR 和 Hydration
v16 新出現的 Hydration(水合)功能是指在伺服器端渲染(server-side rendering, SSR)後,將靜態的 HTML 內容在瀏覽器端「補水」,讓它恢復成可互動的 Angular 應用程式。
簡單來說:
- HTML 預渲染:伺服器先產生完整網頁 HTML,使用者打開網頁時可立即看到內容。
- 啟用hydration:在前端自動將這些 HTML 轉化為可互動的 Angular 元件,無需重新渲染。
這項功能極大地提升了首次載入的速度與 SEO,同時保留 SPA 的互動性。
(v16 為預覽版。 v17 開始進入穩定版,且新的專案如果使用 SSR,將預設啟用 hydration)
Angular v17
新的區塊模板語法 (@if, @switch, @for 等)
推出全新的區塊模板語法(block template syntax),帶來強大且宣告式的 API,支援控制流程、lazy loading 等功能,能有效提升開發者體驗。
新語法由 Angular 編譯器轉換成高效 JavaScript 指令,帶來顯著效能提升。
範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26<!-- @if 範例 -->
@if (isLoggedIn) {
<p>歡迎回來!</p>
} @else {
<p>請先登入。</p>
}
<!-- @switch 範例 -->
@switch (status) {
@case ('loading') {
<p>載入中...</p>
}
@case ('error') {
<p>發生錯誤!</p>
}
@default {
<p>完成!</p>
}
}
<!-- @for 範例 -->
@for (let item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>目前沒有資料。</li>
}- 這邊要特別提到新版 @for 語法強制要求使用 track,並採用全新 diff 演算法,確保更高的 diffing 效能。
- @for 的 track 只需寫成一個表達式,不像以往必須在元件 class 內額外定義方法,語法更簡單易用。
- @for 支援 @empty 區塊,能針對集合為空時快速呈現替代內容。
舊版專案可透過以下 CLI 指令轉換成新版的語法
1
ng generate @angular/core:control-flow
新的延遲載入語法: @defer
Deferrable Views(可延遲載入的視圖) 是 Angular 17 新推出的懶載入機制,利用 block syntax 實現更強大且簡潔的延遲載入功能。
開發者只需一行宣告式語法
@defer
,即可延遲載入元件及其所有依賴,不再需要手動管理 ViewContainerRef、清理、錯誤處理等繁瑣流程。Angular 編譯器會自動將 defer block 內的元件、指令、pipes 轉為動態 import,並管理載入狀態切換。
支援多種觸發條件,包括:
on idle
:瀏覽器空閒時延遲載入 (@defer預設行為)on immediate
:立刻開始延遲載入on timer
: 使用計時器延遲載入on viewport
:元件進入視窗時延遲載入,也可另外指定參考元素on interaction
、on hover
:用戶互動或滑鼠懸停時延遲載入when <expr>
:自訂條件
可用
@placeholder
、@loading
、@error
區塊管理載入前、載入中及失敗的 UI 狀態。可用
prefetch
提前預取依賴。範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35<!-- 最基本的延遲載入區塊 -->
@defer {
<comment-list />
}
<!-- 當區塊進入視窗才開始載入 -->
@defer (on viewport) {
<comment-list />
}
<!-- 當區塊進入視窗才開始載入,並會在瀏覽器空閒時提前預取依賴 -->
@defer (on viewport; prefetch on idle) {
<comment-list />
}
<!-- 當參考元素進入視窗才開始載入 -->
@defer (on viewport(commentsAnchor)) {
<comment-list />
}
<!-- 延遲一段時間後再開始載入(毫秒),並包含 placeholder、載入中與錯誤的狀態處理 -->
@defer (on timer(2000)) {
<heavy-chart />
} @placeholder {
<div class="skeleton-chart">圖表載入準備中...</div>
} @loading {
正在載入圖表…
} @error {
圖表載入失敗,請重試。
}
<!-- 當 isDetailsReady 為 truthy 時才載入 -->
@defer (when isDetailsReady) {
<details-view [details]="details" />
}@defer 注意事項:
- when 從 falsy -> truthy 轉變時觸發一次載入。要注意載入完成後不會自動移除,也不會因為條件再變回 falsy 而回復成 placeholder。
- 可同時設定多個觸發條件(例如
(when condition; on timer(5000); prefetch on idle)
),且任一先達成即開始載入。 - prefetch 不會執行初始化,只抓資源;正式觸發仍需達成觸發條件。
v17 的其他更新
- Signals 等 API 開始陸續進入穩定版本
- 新專案預設啟用 Standalone API,CLI 新增
ng new --standalone
。 - 新專案使用 SSR,預設啟用 hydration。
小結
本篇文章中快速帶過 Angular v15 到 v17 我覺得比較重大的更新,像是 standalone
元件、signals
、新的區塊模板語法(@if, @switch, @for
),以及更強大的 @defer
延遲載入機制。使用這些新東西漸漸替換掉之前的舊有寫法,應能讓我們的開發流程更簡潔、運作效能更好。
下一篇會繼續介紹 v18 之後的重點更新,敬請期待!