1. ก่อนเริ่มต้น
สัญญาณ Angular จะแนะนำพื้นฐานเชิงรับ 3 ประการใน Angular ที่คุณรู้จักและชื่นชอบ ซึ่งช่วยให้การพัฒนาของคุณง่ายขึ้นและช่วยให้คุณสร้างแอปที่เร็วขึ้นโดยค่าเริ่มต้น
สิ่งที่คุณจะสร้าง
- คุณจะได้เรียนรู้เกี่ยวกับพรอมิเทีฟแบบเรียลไทม์ 3 รายการที่มาพร้อมกับ Angular Signals ได้แก่
signal()
,computed()
และeffect()
- ใช้ Angular Signals เพื่อขับเคลื่อนเกม Angular Cipher การเข้ารหัสเป็นระบบสําหรับเข้ารหัสและถอดรหัสข้อมูล ในเกมนี้ ผู้ใช้สามารถถอดรหัสข้อความลับด้วยการลากและวางคำใบ้เพื่อไขปริศนา ปรับแต่งข้อความ และแชร์ URL เพื่อส่งข้อความลับให้เพื่อน
ข้อกำหนดเบื้องต้น
- ความรู้เกี่ยวกับ Angular และ Typescript
- ขอแนะนํา: ดูวิดีโอ Rethinking Reactivity with Signals เพื่อดูข้อมูลเกี่ยวกับคลัง Signals ของ Angular
2. รับโค้ด
ทุกอย่างที่คุณต้องการสำหรับโปรเจ็กต์นี้อยู่ใน Stackblitz เราขอแนะนําให้ใช้ Stackblitz เพื่อทํา Codelab นี้ หรือจะโคลนโค้ดและเปิดในสภาพแวดล้อมการพัฒนาที่ชื่นชอบก็ได้
เปิด Stackblitz และเรียกใช้แอป
หากต้องการเริ่มต้นใช้งาน ให้เปิดลิงก์ Stackblitz ในเว็บเบราว์เซอร์ที่คุณชื่นชอบ
- เปิดแท็บใหม่ในเบราว์เซอร์แล้วไปที่ https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts
- แยก Stackblitz เพื่อสร้างพื้นที่ทํางานที่แก้ไขได้ของคุณเอง Stackblitz ควรเรียกใช้แอปโดยอัตโนมัติ และคุณก็พร้อมใช้งาน
ทางเลือก: โคลนที่เก็บและแสดงแอป
การใช้ VSCode หรือ IDE ในเครื่องเป็นอีกวิธีหนึ่งในการทำงานผ่านโค้ดแล็บนี้
- เปิดแท็บใหม่ในเบราว์เซอร์แล้วไปที่ https://github.com/angular/codelabs/tree/signals-get-started
- แยกและโคลนที่เก็บ แล้วใช้คำสั่ง
cd codelabs/
เพื่อย้ายไปยังที่เก็บ - ตรวจสอบสาขาของโค้ดเริ่มต้นด้วยคำสั่ง
git checkout signals-get-started
- เปิดโค้ดใน VSCode หรือ IDE ที่ต้องการ
- หากต้องการติดตั้ง Dependency ที่จําเป็นสําหรับการเรียกใช้เซิร์ฟเวอร์ ให้ใช้คําสั่ง
npm install
- หากต้องการเรียกใช้เซิร์ฟเวอร์ ให้ใช้คำสั่ง
ng serve
- เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:4200
3. กำหนดพื้นฐาน
จุดเริ่มต้นคือเกม Angular Cipher แต่ยังไม่ทํางาน Angular Signals จะขับเคลื่อนฟังก์ชันการทำงานของเกม
ในการเริ่มต้นใช้งาน ให้อธิบายถึงสิ่งที่คุณจะสร้างในเวอร์ชันที่เสร็จสมบูรณ์แล้ว ได้แก่ Angular Signals Cypher
- ดูข้อความที่เข้ารหัสบนหน้าจอ
- ลากและวางปุ่มตัวอักษรโดยใช้ปุ่มกดเพื่อแก้โจทย์และถอดรหัสข้อความลับ
- เมื่อดำเนินการเสร็จสิ้นแล้ว ให้ดูว่าข้อความอัปเดตเพื่อถอดรหัสข้อความลับเพิ่มเติมอย่างไร
- คลิกปรับแต่งเพื่อเปลี่ยนผู้ส่งและข้อความ แล้วคลิกสร้างและคัดลอก URL เพื่อดูค่าบนหน้าจอและการเปลี่ยนแปลง URL
- โบนัส: คัดลอกและวาง URL ในแท็บใหม่ หรือแชร์กับเพื่อน และดูว่าผู้ส่งและข้อความใน URL จัดเก็บอย่างไร
4. กำหนด Signals แรก()
สัญญาณคือค่าที่บอก Angular ได้เมื่อมีการเปลี่ยนแปลง สัญญาณบางรายการเปลี่ยนแปลงได้โดยตรง ขณะที่สัญญาณอื่นๆ จะคํานวณค่าจากค่าของสัญญาณอื่นๆ สัญญาณเหล่านี้จะร่วมกันสร้างกราฟกำกับของความสัมพันธ์ซึ่งจำลองการไหลของข้อมูลในแอป
Angular สามารถใช้การแจ้งเตือนจากสัญญาณเพื่อให้รู้ว่าต้องตรวจหาการเปลี่ยนแปลงคอมโพเนนต์ใดหรือเพื่อเรียกใช้ฟังก์ชัน effect ที่คุณกำหนด
แปลง superSecretMessage
เป็น signal()
superSecretMessage
คือค่าใน MessageService
ที่กําหนดข้อความลับที่ผู้เล่นจะถอดรหัส ซึ่งปัจจุบันค่าดังกล่าวไม่ได้แจ้งให้แอปทราบถึงการเปลี่ยนแปลง ดังนั้นปุ่มปรับแต่งจะใช้งานไม่ได้ คุณแก้ปัญหานี้ได้โดยใช้สัญญาณ
การทำ superSecretMessage
เป็นสัญญาณจะช่วยให้คุณแจ้งเตือนส่วนต่างๆ ของแอปที่จำเป็นต้องทราบเมื่อข้อความมีการเปลี่ยนแปลงได้ เมื่อปรับแต่งข้อความในกล่องโต้ตอบ คุณจะตั้งค่าสัญญาณเพื่ออัปเดตส่วนที่เหลือของแอปด้วยข้อความใหม่
หากต้องการกําหนดสัญญาณแรก ให้ทําตามขั้นตอนต่อไปนี้ในส่วนความคิดเห็น TODO(1): Define your first signal()
ของแต่ละไฟล์
- ในไฟล์
service.message.ts
ให้ใช้ไลบรารี Signals เพื่อทําให้superSecretMessage
ตอบสนองต่อเหตุการณ์ต่อไปนี้
src/app/secret-message/service.message.ts
superSecretMessage = signal(
'Angular Signals are in developer preview in v16 today!'
);
ซึ่งจะแจ้งให้คุณนําเข้า signal
จาก @angular/core
โดยอัตโนมัติ หากรีเฟรชหน้า คุณอาจพบข้อผิดพลาดจากที่อ้างถึง superSecretMessage
ก่อนหน้านี้ เนื่องจากคุณเปลี่ยนประเภท superSecretMessage
จาก string
เป็น SettableSignal<string>
คุณสามารถแก้ไขปัญหานี้ได้โดยการเปลี่ยนการอ้างอิงทั้งหมดของ superSecretMessage
ให้ใช้ Signals API เรียก Signal getter superSecretMessage()
ในทุกที่ที่คุณอ่านค่า และไม่ว่าคุณจะเขียนค่าไว้ที่ใดก็ตาม ให้ใช้ .set
API ใน SettableSignal
เพื่อตั้งค่าใหม่สำหรับข้อความ
- ในไฟล์
secret-message.ts
และservice.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()
สำรวจสัญญาณอีก 2 รายการ
- โปรดทราบว่าคุณมีสัญญาณอื่นๆ อีก 2 รายการในแอป
src/app/cipher/service.cipher.ts
cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);
CipherService
จะกำหนดสัญญาณ cipher
ซึ่งเป็นการจับคู่แบบสุ่มของคู่คีย์-ค่าของตัวอักษร 1 ตัวจากตัวอักษรทั้งหมดกับตัวอักษร cipher
ตัวใหม่ คุณใช้ตัวเลือกนี้เพื่อสับเปลี่ยนข้อความและระบุว่าผู้เล่นพบการจับคู่ที่ตรงกันในแป้นพิมพ์หรือไม่
นอกจากนี้ คุณยังมีสัญญาณ decodedCipher
ของคู่คีย์-ค่าที่ถอดรหัสสำเร็จซึ่งคุณจะเพิ่มเข้าไปเมื่อผู้เล่นไขรหัสได้
คุณสมบัติเด่นที่เป็นเอกลักษณ์และทรงพลังของการออกแบบคลังสัญญาณของ Angular คือคุณสามารถทำให้เกิดความรู้สึกได้ในทุกที่ คุณได้กำหนดสัญญาณไว้ในบริการของแอปแล้ว และจะใช้สัญญาณดังกล่าวในเทมเพลต คอมโพเนนต์ ไปป์ บริการอื่นๆ หรือที่ใดก็ตามที่คุณสามารถเขียนโค้ดของแอปพลิเคชันได้ ไม่มีการจํากัดหรือผูกกับขอบเขตคอมโพเนนต์
ยืนยันการเปลี่ยนแปลง
- คุณต้องดำเนินการอีก 1 ขั้นตอนก่อนที่แอปจะใช้งานได้ ในระหว่างนี้ ให้ลองเพิ่ม
console.log()
ในส่วนต่างๆ ของแอปเพื่อดูว่าระบบตั้งค่าsuperSecretMessage
ใหม่อย่างไร
5. กำหนด computed() รายการแรก
ในหลายสถานการณ์ คุณอาจพบว่าตัวเองดึงสถานะมาจากค่าที่มีอยู่ คุณควรอัปเดตสถานะแบบอนุมานเมื่อค่าที่เกี่ยวข้องมีการเปลี่ยนแปลง
computed()
ช่วยให้คุณแสดงสัญญาณที่ดึงค่ามาจากสัญญาณอื่นๆ ได้
แปลง solvedMessage
เป็น computed()
solvedMessage
แปลค่า secretMessage
จากที่เข้ารหัสเป็นการถอดรหัสโดยใช้สัญญาณ decodedCipher
ซึ่งเจ๋งกว่าตรงที่คุณเห็นว่าคุณกำลังดึงข้อมูลค่าที่คำนวณแล้วจากค่าที่คำนวณแล้วอีกรายการหนึ่ง ดังนั้นเมื่อใดก็ตามที่สัญญาณภายในบริบทการตอบสนองที่แมปไว้มีการเปลี่ยนแปลง ระบบจะแจ้งให้ทราบถึงข้อมูลที่ต้องพึ่งพา
ปัจจุบัน solvedMessage
จะไม่อัปเดตเมื่อคุณเปลี่ยน secretMessage
, decodedCipher
หรือ superSecretMessage
คุณจึงไม่เห็นการอัปเดตบนหน้าจอเมื่อผู้เล่นไขรหัส
การกำหนดให้ solvedMessage
เป็นการคำนวณจะเป็นการสร้างบริบทเชิงรับ เพื่อให้เมื่ออัปเดตข้อความหรือแก้โจทย์การเข้ารหัส จะรับการอัปเดตสถานะจากทรัพยากร Dependency ที่ติดตามได้
หากต้องการแปลง solvedMessage
เป็น computed()
ให้ทําตามขั้นตอนต่อไปนี้ในส่วนความคิดเห็น TODO(2): Define your first computed()
ของแต่ละไฟล์
- ในไฟล์
service.message.ts
ให้ใช้ไลบรารี Signals เพื่อทำให้solvedMessage
โต้ตอบ:
src/app/secret-message/service.message.ts
solvedMessage = computed(() =>
this.translateMessage(
this.secretMessage(),
this.cipher.decodedCipher()
)
);
ซึ่งจะแจ้งให้คุณนําเข้า computed
จาก @angular/core
โดยอัตโนมัติ หากรีเฟรชหน้าเว็บ คุณอาจพบข้อผิดพลาดในตำแหน่งที่คุณอ้างอิงถึง solvedMessage
ก่อนหน้านี้ เนื่องจากคุณเปลี่ยนประเภทของ superSecretMessage
จาก string
เป็น Signal<string>
ซึ่งเป็นฟังก์ชัน คุณแก้ไขปัญหานี้ได้โดยเปลี่ยนการอ้างอิง solvedMessage
ทั้งหมดเป็น solvedMessage()
- ในไฟล์
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>
โปรดทราบว่า solvedMessage
ไม่ใช่ SettableSignal
ซึ่งต่างจาก superSecretMessage
ตรงที่คุณไม่สามารถเปลี่ยนค่าได้โดยตรง แต่ระบบจะอัปเดตค่าทุกครั้งที่มีการอัปเดตสัญญาณการพึ่งพา (secretMessage
และ decodedCipher
)
สำรวจcomputed()
ฟังก์ชันอีก 2 รายการ
- โปรดทราบว่าคุณมีค่าที่คำนวณแล้วอีก 2 ค่าในแอป
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
ที่คำนวณแล้ว superSecretMessage
ที่เข้ารหัสโดย cipher
ที่ผู้เล่นต้องไข
CipherService
กำหนด unsolvedAlphabet
ที่คำนวณแล้ว ซึ่งเป็นรายการตัวอักษรทั้งหมดที่ผู้เล่นยังไม่ได้ไข ซึ่งมาจากรายการคีย์การเข้ารหัสที่ไขแล้วใน decodedCipher
ยืนยันการเปลี่ยนแปลง
เมื่อ superSecretMessage
เป็นสัญญาณและ solvedMessage
เป็นระบบที่คำนวณแล้ว แอปก็ควรใช้งานได้ ทดสอบฟังก์ชันการทำงานของเกม
- ลากและวาง
LetterGuessComponent
ลงในLetterKeyComponent
ในCipherComponent
เพื่อแก้ปัญหาการเข้ารหัสและถอดรหัสข้อความลับ - ดูว่า
SecretMessageComponent
อัปเดตอย่างไรเมื่อคุณถอดรหัสข้อความลับได้มากขึ้น - คลิกปรับแต่งเพื่อเปลี่ยนผู้ส่งและข้อความ แล้วคลิกสร้างและคัดลอก URL เพื่อดูค่าบนหน้าจอและการเปลี่ยนแปลง URL
- โบนัส: คัดลอกและวาง URL ในแท็บใหม่ หรือแชร์กับเพื่อน และดูว่าผู้ส่งและข้อความใน URL จัดเก็บอย่างไร
6. เพิ่ม effect() รายการแรก
บางครั้งคุณอาจต้องการให้การดำเนินการบางอย่างเกิดขึ้นเมื่อสัญญาณมีค่าใหม่ effect()
ช่วยให้คุณกําหนดเวลาและเรียกใช้ฟังก์ชันตัวแฮนเดิลเพื่อตอบสนองต่อการเปลี่ยนแปลงของสัญญาณได้
เพิ่มกระดาษ confetti เมื่อไขรหัสสำเร็จ
เมื่อแอปใช้งานได้แล้ว คุณสามารถเพิ่มความสนุกด้วยการเพิ่มกระดาษโปรยเมื่อไขรหัสและถอดรหัสข้อความลับได้แล้ว
หากต้องการเพิ่มกระดาษโปรย ให้ทำตามขั้นตอนต่อไปนี้ในส่วนความคิดเห็น TODO(3): Add your first effect()
- ในไฟล์
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()
เอฟเฟกต์ช่วยให้คุณกําหนดเวลาฟังก์ชันกระดาษโปรยภายในบริบทแบบรีแอ็กทีฟเพื่อติดตามและประเมินใหม่เมื่อมีการอัปเดตทรัพยากร Dependency
ยืนยันการเปลี่ยนแปลง
- ลองถอดรหัส (เคล็ดลับ: คุณเปลี่ยนข้อความให้สั้นลงเพื่อทดสอบได้เร็วขึ้น) ฟีเจอร์นี้จะแสดงป๊อปอัปกระดาษสีโปรยปรายเพื่อแสดงความยินดีกับ
effect()
รายการแรกของคุณ
7. ยินดีด้วย
ตอนนี้คุณก็พร้อมที่จะถอดรหัสและแชร์ข้อความลับด้วย Angular Cipher แล้ว หากมีข้อความถึงทีม Angular แท็กโซเชียลมีเดียของเราที่ @Angular เพื่อให้เราถอดรหัสได้ 🎉
ตอนนี้คุณมีองค์ประกอบพื้นฐานแบบเรียลไทม์ใหม่ 3 รายการในกล่องเครื่องมือ Angular เพื่อช่วยลดความซับซ้อนในการพัฒนาและสร้างแอปที่เร็วขึ้นโดยค่าเริ่มต้น
ดูข้อมูลเพิ่มเติม
ลองดู Codelab เหล่านี้
อ่านเอกสารต่อไปนี้
- Angular.io
- Rethinking Reactivity with Signals (Google I/O 2023)
- มีอะไรใหม่ใน Angular (Google I/O 2023)