開始使用 Angular Signals

1. 事前準備

黑色 Angular 標誌

Angular Signals 為您熟悉喜愛的 Angular 引進三種反應式原始元素,簡化開發作業,並預設加快應用程式建構速度。

建構項目

  • 您將瞭解 Angular 訊號引進的三種回應原始元素:signal()computed()effect()
  • 使用 Angular 信號為 Angular Cipher 遊戲提供動力。密碼是用於加密及解密資料的系統。在這個遊戲中,使用者可以拖曳並放置線索來解開密碼,然後自訂訊息並分享網址,將密碼訊息傳送給朋友。

Angular Cypher 遊戲採用復古的綠色遊戲主機,螢幕上顯示隱藏訊息:「Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!」。

必要條件

2. 取得程式碼

這個專案所需的一切都包含在 Stackblitz 中。建議您使用 Stackblitz 完成本程式碼研究室的課程。或者,您也可以複製程式碼,並在喜愛的開發環境中開啟。

開啟 Stackblitz 並執行應用程式

如要開始使用,請在您慣用的網路瀏覽器中開啟 Stackblitz 連結:

  1. 開啟新的瀏覽器分頁,然後前往 https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
  2. 使用 Stackblitz 建立自己的可編輯工作區。Stackblitz 應會自動執行應用程式,您就可以開始使用了!

替代做法:複製存放區並提供應用程式服務

使用 VSCode 或本機 IDE 是執行本程式碼研究室的替代方法:

  1. 開啟新的瀏覽器分頁,然後前往 https://github.com/angular/codelabs/tree/signals-get-started
  2. 建立分支並複製存放區,並使用 cd codelabs/ 指令來移至存放區。
  3. 查看包含 git checkout signals-get-started 指令的範例程式碼分支。
  4. 在 VSCode 或您偏好的 IDE 中開啟程式碼。
  5. 如要安裝執行伺服器所需的依附元件,請使用 npm install 指令。
  6. 如要執行伺服器,請使用 ng serve 指令。
  7. 開啟瀏覽器分頁並前往 http://localhost:4200

3. 建立基準

您的起點是 Angular Cipher 遊戲,但目前尚未運作。Angular 信號可協助遊戲功能。

以復古綠色遊戲主機風格設計的 Angular Cypher 遊戲,畫面上有隱藏訊息「Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!」

首先,請逐步瞭解即將建構產品的完成版本:Angular Signals Cypher

  1. 查看畫面上的密碼訊息。
  2. 在鍵盤中拖曳並放置字母按鈕,以解開密碼並解碼秘密訊息。
  3. 成功後,請查看訊息如何更新,以便解碼更多機密訊息。
  4. 按一下 [自訂] 變更寄件者和訊息,然後按一下「建立及複製網址」,即可查看畫面上的值和網址的變更。
  5. 額外資訊:複製網址並貼到新分頁,或與朋友分享,看看網址中儲存了哪些寄件者和訊息。

Angular Cypher 遊戲的 GIF,畫面中以解碼的方式顯示隱藏訊息,例如「Angular Signals is in the developer Previews are in developer Preview!!」

4. 定義第一個 signal()

信號是一種值,可在 Angular 變動時通知對方。有些信號可以直接變更,有些則會根據其他信號的值計算值。信號會共同建立依附性圖表,藉此模擬資料在應用程式中流動的方式。

Angular 可使用信號傳送的通知,瞭解需要偵測變更的元件,或執行您定義的 effect 函式。

superSecretMessage 轉換為 signal()

superSecretMessageMessageService 中的值,用於定義玩家解碼的密件。目前,該值不會通知應用程式變更,因此「自訂」按鈕無法正常運作。你可以透過信號解決這個問題。

superSecretMessage 設為訊號,即可通知應用程式部分依據訊息變更時間。在對話方塊中自訂訊息時,您會設定信號,以便使用新訊息更新應用程式的其餘部分。

如要定義第一個信號,請在每個檔案的 TODO(1): Define your first signal() 註解下方執行下列步驟:

  1. service.message.ts 檔案中,使用 Signals 程式庫讓 superSecretMessage 具備回應性:

src/app/secret-message/service.message.ts

superSecretMessage = signal(
  'Angular Signals are in developer preview in v16 today!'
);

系統會自動提示您從 @angular/core 匯入 signal。如果重新整理頁面,您可能會在先前參照 superSecretMessage 的部分遇到錯誤。這是因為您已將 superSecretMessage 的類型從 string 變更為 SettableSignal<string>。您可以將 superSecretMessage 的所有參照變更為 Signals API,藉此修正此問題。無論您在何處讀取值,都必須呼叫 Signal getter superSecretMessage()。無論您在何處寫入值,請在 SettableSignal 上使用 .set API,為訊息設定新值。

  1. secret-message.tsservice.message.ts 檔案中,將所有 superSecretMessage 參照更新為 superSecretMessage()

src/app/secret-message/secret-message.ts

// Before
this.messages.superSecretMessage
this.messages.superSecretMessage = message;

// After
this.messages.superSecretMessage()
this.messages.superSecretMessage.set(message);

src/app/secret-message/service.message.ts

// Before
this.superSecretMessage

// After
this.superSecretMessage()

探索其他兩個信號

  • 請注意,您的應用程式中還有兩個其他信號:

src/app/cipher/service.cipher.ts

cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);

CipherService 會定義 cipher 信號,這是隨機產生的鍵/值組合,將字母表中的一個字母對應至新的 cipher 字母。您可以使用這個方法將訊息加密,並判斷玩家是否在鍵盤上找到相符項目。

您也擁有 decodedCipher 信號,可在玩家解開密碼時,新增成功解碼的鍵/值組合。

Angular 信號程式庫設計的獨特且強大的屬性,就是您可以在任何地方引入回應性。您在應用程式的服務中定義了信號一次,這些信號可用於範本、元件、管道、其他服務,或是可編寫應用程式程式碼的任何位置。不受限制,也不受元件範圍限制。

驗證變更

  • 應用程式運作前,您還需要執行一個步驟。目前,請嘗試在應用程式的不同部分新增 console.log(),看看新的 superSecretMessage 如何設定。

Stackblitz 中顯示的 console.log() 訊息,顯示 superSecretMessage 正確記錄新訊息。

5. 定義第一個 computed()

在許多情況下,您可能會從現有值衍生狀態。在相依值變更時,最好更新衍生狀態。

使用 computed(),即可透過宣告方式表示從其他信號衍生價值的信號。

solvedMessage 轉換為 computed()

solvedMessage 會使用 decodedCipher 信號,轉換編碼為已解碼的 secretMessage 值。

這點特別有趣,因為您可以看到自己是根據另一個計算結果衍生出計算結果,因此只要對應的回應式內容變更,就會通知相關依附元件。

目前,變更 secretMessagedecodedCiphersuperSecretMessage 時,solvedMessage 不會更新。因此,當玩家破解密碼時,您不會看到畫面更新。

計算 solvedMessage 即可建立回應式結構定義,以便在更新訊息或解決加密作業時,從已追蹤的依附元件衍生狀態更新。

如要將 solvedMessage 轉換為 computed(),請在每個檔案的 TODO(2): Define your first computed() 註解下方執行下列步驟:

  1. service.message.ts 檔案中,使用 Signals 程式庫讓 solvedMessage 具備回應性:

src/app/secret-message/service.message.ts

solvedMessage = computed(() =>
  this.translateMessage(
    this.secretMessage(), 
    this.cipher.decodedCipher()
  )
);

系統會自動提示您從 @angular/core 匯入 computed。如果重新整理頁面,您可能會在先前參照 solvedMessage 的部分遇到錯誤。這是因為您已將 superSecretMessage 的類型從 string 變更為 Signal<string> (函式)。如要修正這個問題,請將 solvedMessage 的所有參照變更為 solvedMessage()

  1. secret-message.ts 檔案中,將 solvedMessage 的所有參照更新為 solvedMessage()

src/app/secret-message/secret-message.ts

// Before
<span *ngFor="let char of this.messages.solvedMessage.split(''); index as i;" [class.unsolved]="this.messages.solvedMessage[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

// After
<span *ngFor="let char of this.messages.solvedMessage().split(''); index as i;" [class.unsolved]="this.messages.solvedMessage()[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

請注意,solvedMessagesuperSecretMessage 不同,它不是 SettableSignal,因此無法直接變更其值。相反地,只要其中一個依附元件信號 (secretMessagedecodedCipher) 更新,其值就會保持最新狀態。

探索其他兩個 computed() 函式

  • 請注意,應用程式中還有兩個其他計算值:

src/app/secret-message/service.message.ts

secretMessage = computed(() => 
  this.translateMessage(
    this.superSecretMessage(),
    this.cipher.cipher()
  )
);

src/app/cipher/service.cipher.ts

unsolvedAlphabet = computed(() =>
  ALPHABET.filter(
    (letter) => !this.decodedCipher().find((guess) => guess.value === letter)
  )
);

MessageService 會定義計算的 secretMessage (由玩家設法解決的 cipher 編碼) superSecretMessage

CipherService 會定義 unsolvedAlphabet 計算結果,也就是玩家尚未解開的所有字母清單,這會從 decodedCipher 中已解開的密碼金鑰清單衍生而來。

驗證變更

superSecretMessage 是信號,solvedMessage 是計算值,因此應用程式應該可以正常運作!測試遊戲功能:

  1. LetterGuessComponent 拖曳到 CipherComponent 中的 LetterKeyComponent,即可解析密鑰並解碼密鑰。
  2. 瞭解隨著您解碼更多密件內容時,SecretMessageComponent 如何更新。
  3. 按一下「自訂」變更「寄件者」和「訊息」,然後按一下「建立並複製網址」,查看畫面上的值和網址變更。
  4. 額外資訊:複製網址並貼到新分頁,或與朋友分享,看看網址中儲存了哪些寄件者和訊息。

Angular Cypher 遊戲的 GIF,畫面中以解碼的方式顯示隱藏訊息,例如「Angular Signals is in developer Previews are in developer Preview!!」

6. 新增第一個 effect()

有時,您可能會想在信號有新值時發生某些情況。使用 effect() 時,您可以根據信號變更的情況,安排及執行處理常式函式。

在解開密碼時加入灑紙

應用程式現在已可正常運作,您可以新增一些有趣的效果,例如在解開密碼並解碼秘密訊息時顯示灑紙。

如要新增灑紙花特效,請在 TODO(3): Add your first effect() 註解下方執行下列步驟:

  1. cipher.ts 檔案中,排定效果,在訊息解碼時加入彩帶:

src/app/cipher/cipher.ts

import * as confetti from 'canvas-confetti';

ngOnInit(): void {
  ...

  effect(() => {
    if (this.messages.superSecretMessage() === this.messages.solvedMessage()) {
      var confettiCanvas = document.getElementById('confetti-canvas');
      confetti.create()(confettiCanvas, { particleCount: 100 });
    }
  });
}

請注意,這個效果如何取決於信號和計算的值:this.messages.superSecretMessage()this.messages.solvedMessage()

Effect 可協助您在回應式內容中排程灑紙花函式,以便追蹤並重新評估依附元件更新的時間。

驗證變更

  • 請試著解開加密方式 (提示:將訊息改成更精簡的內容,即可更快進行測試!)。系統會顯示彩色紙碎屑圖案,恭喜你獲得第一個 effect()

動畫 GIF 檔案:在 Angular Cypher 遊戲中,畫面上會解碼隱藏訊息,顯示「Confetti time!」字樣,並在訊息解開時發射彩色紙花。

7. 恭喜!

Angular Cipher 現已準備好解碼及分享機密訊息!想傳送訊息給 Angular 團隊嗎?請標記我們的社群媒體帳號 @Angular,方便我們解碼!🎉

Angular Cypher 遊戲完成解決,「Angular Signals is in v16 in the developer Previews!」(Angular Signals 目前在開發人員預覽版 v16 已啟用!) 畫面上,顯示隱藏訊息來解決問題!

Angular 工具箱現在提供三個新的回應原始元素,可簡化開發作業,並預設加快應用程式建構速度。

瞭解詳情

請查看下列程式碼研究室:

請參閱下列資料: