今天直接進入Live Coding的部分,有關影片內容可以看
前幾天帶大家理順專案的流程,昨天定義好前端資料格式後,然後進入正式開發流程。
從StackOverflow 複製程式碼,免費;知道貼到哪邊,無價。
import {
CreatRoomRequest,
FindRoomRequest,
} from 'src/app/shared/api/api.interface';
import { ApiService } from 'src/app/shared/api/api.service';
import { TwmhCoreService } from 'src/app/shared/service/twmh-core.service';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { BehaviorSubject } from 'rxjs';
import { v4 as uuidv4 } from 'uuid';
import { Router } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
/**
* 玩家唯一識別碼
*/
uuid: string;
/**
* 表單送出識別
* TODO 改為Form Submit
*/
formSubmited = false;
/**
* 載入畫面中
*/
pageLoading$ = new BehaviorSubject<boolean>(false);
/**
* 房間表單
*/
roomForm: FormGroup;
constructor(
private fb: FormBuilder,
private apiService: ApiService,
private router: Router,
private twmhCoreService: TwmhCoreService
) {
// 先取得 LocalStorage 的UUID, 如果未取得就是Null
this.uuid = localStorage.getItem('TWMHUUID');
if (!!this.uuid) {
// 有uuid的話,就檢查本玩家是否有已經在房間內。
this.findUuidRoom(this.uuid);
} else {
// 沒有uuid的話,就生成一組並存入LocalStorage。
this.uuid = uuidv4();
localStorage.setItem('TWMHUUID', this.uuid);
}
// 將UUID存入共用Service
this.twmhCoreService.uuid$.next(this.uuid);
}
ngOnInit(): void {
// 初始化的時候建立表單
// 表單的UUID用來傳送此玩家的識別碼並存入資料庫。
// RoomID為用來搜尋房間用的。
this.roomForm = this.fb.group({
uuid: this.uuid,
roomID: ['', [Validators.required, Validators.min(4)]],
});
}
/**
* 使用房間號碼來尋找房間的函數
*/
findRoom(): void {
// 跳出載入畫面
this.pageLoading$.next(true);
// 標示表單已送出
this.formSubmited = true;
// 整理請求的資料格式
const requestData: FindRoomRequest = this.roomForm.value;
// 送出資料
this.apiService.findRoom$(requestData, 'success').subscribe(
(roomData) => {
// 將回傳回來的房間資料放入共用Service內
this.twmhCoreService.room$.next(roomData);
// 跳轉頁面到房間內的玩家頁面
this.router.navigate(['room', 'player']);
},
(error) => {
this.twmhCoreService.openSnackBar(error);
}
);
}
/**
* 使用已經存在的UUID來尋找原本玩家是否有在房間的函數
* @param uuid 玩家唯一識別碼
*/
findUuidRoom(uuid: string): void {
console.log(uuid);
}
/**
* 創立房間
*/
createRoom(): void {
// 跳出載入畫面
this.pageLoading$.next(true);
// 標示表單已送出
this.formSubmited = true;
// 整理請求的資料格式
const requestData: CreatRoomRequest = {
uuid: this.uuid,
};
// 送出資料
this.apiService.createRoom$(requestData, 'success').subscribe(
(roomData) => {
// 將回傳回來的房間資料放入共用Service內
this.twmhCoreService.room$.next(roomData);
// 跳轉頁面到房間內的玩家頁面
this.router.navigate(['room', 'host']);
},
(error) => {
this.twmhCoreService.openSnackBar(error);
}
);
}
}
就像是前面所說的,有了介面要把後面資料理順,在填寫資料的部分我們需要限制使用者至少填入4個字才尋找房間,而按鈕需要先鎖定,創建房間的部分則是不用受到限制。
所以我們會需要先創建動態表單,我們要保持資料處理(Data)跟範本(HTML)分開的原則,所以定義出ReactiveForm
// 初始化的時候建立表單
// 表單的UUID用來傳送此玩家的識別碼並存入資料庫。
// RoomID為用來搜尋房間用的。
this.roomForm = this.fb.group({
uuid: this.uuid,
roomID: ['', [Validators.required, Validators.min(4)]],
});
定義好Room ID是必須要填入的就可以做驗證了!
接下來就直接看驗證流程
接下來綁上按鈕的會觸發的函數之後,我們連接到findRoom
這個函數,然後建立好之後,開始寫功能,我們寫功能之前會需要有一個API來做測試,而目前API也都還沒建立出來,於是我們使用Observable
的特性來寫一個假的API,並且將API的Service給實作出來,並將測試用的假資料建立,定義好請求跟回傳的interface,
export interface FindRoomRequest {
roomID: string;
uuid: string;
}
export interface Room {
id: string;
roomID: string;
players: RoomPlayers[];
currentRound: number;
currentState?: RoomState;
}
我們預設送出跟回傳的格式為這樣,並寫好測試資料,
import { Room } from './api.interface';
// 測試用資料
const createRoomSuccess: Room = {
id: '1',
roomID: 'TWMH',
players: [
{
uuid: '',
isHost: true,
playerNumber: 0,
role: '主持人',
},
],
currentRound: 0,
};
export const createRoomTestingData = {
success: createRoomSuccess,
};
然後在Api服務內引入測試資料來做假的API
findRoom$ = (requestData: FindRoomRequest, dev?: string): Observable<Room> =>
of(dev ? apiTestData.createRoomTestingData[dev] : '沒有API').pipe(
delay(1000)
);
並加上 delay
延遲來檢查請求跟載入的過場時間,這樣我們就可以有假的API來做回傳的測試資料了。
/**
* 使用房間號碼來尋找房間的函數
*/
findRoom(): void {
// 跳出載入畫面
this.pageLoading$.next(true);
// 標示表單已送出
this.formSubmited = true;
// 整理請求的資料格式
const requestData: FindRoomRequest = this.roomForm.value;
// 送出資料
this.apiService.findRoom$(requestData, 'success').subscribe(
(roomData) => {
// 將回傳回來的房間資料放入共用Service內
this.twmhCoreService.room$.next(roomData);
// 跳轉頁面到房間內的玩家頁面
this.router.navigate(['room', 'player']);
},
(error) => {
this.twmhCoreService.openSnackBar(error);
}
);
}
秉持著程式碼就是文件的概念填寫,我們按下按鈕之後觸發載入畫面動畫,然後將表單標示為送出,並將請求資料整理好之後送出。
而回傳回來的Room資料放到共用的服務之後就可以跳轉頁面到房間內了!
程式碼就算寫得跟文件一樣,還是要寫文件,因為架構是你自己的世界。
/**
* 創立房間
*/
createRoom(): void {
// 跳出載入畫面
this.pageLoading$.next(true);
// 標示表單已送出
this.formSubmited = true;
// 整理請求的資料格式
const requestData: CreatRoomRequest = {
uuid: this.uuid,
};
// 送出資料
this.apiService.createRoom$(requestData, 'success').subscribe(
(roomData) => {
// 將回傳回來的房間資料放入共用Service內
this.twmhCoreService.room$.next(roomData);
// 跳轉頁面到房間內的玩家頁面
this.router.navigate(['room', 'host']);
},
(error) => {
this.twmhCoreService.openSnackBar(error);
}
);
}
創建房間功能在畫面上就一個按鈕,我們按下按鈕之後觸發載入畫面動畫,然後將表單標示為送出,並將請求資料(也就是Host本身的UUID)整理好之後送出。
而回傳回來的Room資料放到共用的服務之後就可以跳轉頁面到房間內了!
今天帶大家把入口頁面開發完成,接下來就是要帶大家進入房間廝殺!!也是本專案最複雜的地方,明天會帶大家玩主持人畫面開發!