2024-07-11|閱讀時間 ‧ 約 29 分鐘

〖網頁挑戰〗 What's the country

What's the country

What's the country

又是 Frontend Mentor 的挑戰!
這次要寫一個網站,讓使用者可以查詢國家,並且顯示國旗、人口、首都、語言、幣別等資料。原始檔案提供了 JSON 檔,或是可以去串接 REST Countries API,動態取得並呈現各國的資料,基本上看我們要怎麼寫都可以。
在 Frontend Mentor 挑戰中有分五個等級: Newby、Junior、Intermediate、Advanced、Guru,這次的挑戰是..Advanced, 先醜哭乙次(?),我也太勇敢了吧!雖然我只能挑戰到這個等級,因為 Guru 就要花錢了(喂—)

這次挑戰內容:

  • 在首頁渲染所有國家的小卡片
  • 用名稱搜尋國家
  • 用州別篩選出國家
  • 點擊小卡片就能看見國家的詳細資料
  • 在詳細資料中點擊相鄰國家,即可跳到該國家的詳細資料
  • 切換黑夜模式

HTML + CSS 切版

這次的重點是串接 API,所以切版的部分我就不再贅述。

<header>
<a>Where in the world?</a>
<button>Dark Mode</button>
</header>

上方是一個 header:
裡面放首頁連結<a>跟切換模式的<button>

<main>
<div>
<!-- search bar -->
<!-- filter box -->
</div>
<div>
<!-- countries card container -->
</div>
</main>

中間的 main:
放入搜尋和篩選工具
再來放入國家的小卡片們

最底下就是 footer,寫版權文字的地方。



串接 REST Countries API

首先進入 rest countries API 網站,閱讀一下文檔,才知道要怎麼串:

確認串接端點

文檔中都會寫可以從哪個端點取得什麼資料,對第一次串 API 的孩紙來說一定會毫無頭緒,不知道從何下手,,我的話會把端點路徑直接丟到網址列去看資料的結構,然後會得到讓人視力下降的頁面(?)

以上就是把空格縮排都刪除的 JSON 文字

因為現在的資料以 JSON 的數據格式為主,這裡推薦用 Chrome 擴充功能 JSON Viewer Pro 可以直接把密密麻麻的 JSON 文字轉換成好閱讀的畫面:

綠色顧眼睛

這時候我們可以比對最初的設計畫面,一邊比對資料結構,才不會抓了資料下來,才發現跟自己要的不一樣(哭)

現在來回頭看一下挑戰內容,看哪些端點適合用來完成挑戰:

  • 在首頁渲染所有國家的小卡片

這邊就用所有資料的端點:https://restcountries.com/v3.1/all

  • 用名稱搜尋國家

用名稱取得資料:https://restcountries.com/v3.1/name/{name}
後方的 {name} 可以替換國家名稱,想找韓國就是 https://restcountries.com/v3.1/name/korea
只要名稱裡面有包含搜尋的文字,都會跳出資料,所以除了南韓也會找到北韓 :)

  • 用州別篩選出國家

用洲名取得資料:https://restcountries.com/v3.1/region/{region}

  • 在詳細資料中點擊相鄰國家,即可跳到該國家的詳細資料

從資料結構中可以知道,相鄰國家給的資料是國家代碼,所以我們要有一個端點是以國家代碼取得資料:https://restcountries.com/v3.1/alpha/{code}

接下來寫 JavaScript 吧。



JavaScript - 非同步請求

JS 是單線程程式語言,也就是一次執行一行程式碼,執行完成才會進入下一行,假設今天我開啟網頁時,這個網頁需要去向遠端伺服器請求資料,這時候單線程的 JS 就會等待資料回傳回來(執行完成),才執行下一行,使用者就必須在螢幕前等..一直等..繼續等..

想像起來有多浪費生命!

於是非同步請求就這樣產生啦,當 JS 遇到非同步程式碼,非同步程式碼會被放到執行環境中,並從 Stack 中脫離。當非同步程式碼執行完成時,會把要執行的 callback 放到 Callback Queue 中。最後等到 Stack 已經沒有需要執行的程式碼時,再去執行 Callback Queue 中的函式。

或是可以想像一下:
你是一個咖啡店店員,要做的事是點餐、收銀、沖咖啡,出杯,如果今天你必須完成這個循環才能為下一位客人點餐,整個產線就會堵塞,這就是同步程式碼,一切都靠你自己完成,一次只能做一件事。
但是今天你點完餐後,先去咖啡機按下沖煮咖啡,接下來沖咖啡的事就是機器的事,而你又可以繼續為下一個客人點餐,不僅會減少排隊時間,還可以同時煮很多人的咖啡,這就是非同步程式碼,你把需要花時間處理的事交給了咖啡機。

所以很多時候,我們都會依賴其他伺服器提供的資料,就必須使用非同步方法來請求資料。

fetch 獲取數據

fetch 是非同步方法,用在與其他 API 對接獲取數據時使用,返回一個 Promise。

使用 fetch 時,因為要等待回應,所以還沒有獲取任何數據,
為此建立一個容器 - Promise,用來放置未來回傳的結果。

現在常用 async-await 語法糖來包裝非同步程式碼,看起來比較好閱讀:

// 定義端點的 URL​
const BASE_URL = 'https://restcountries.com/v3.1'

// 將非同步函式包裝在裡面 開頭寫下關鍵字 async
const getAllCountries = async function () {
// ...
}

裡面包一層 try-catch 錯誤處理,抓取錯誤:

const BASE_URL = "https://restcountries.com/v3.1";

const getAllCountries = async function () {
//裡面包一層 try-catch
try {
// 正常執行程式碼
} catch (err) {
// 有錯誤時 在 console 列出錯誤​
console.error(err);
}
};

接著就把 fetch 方法寫進去:

const BASE_URL = "https://restcountries.com/v3.1";

const getAllCountries = async function () {
try {
const res = await fetch(`${BASE_URL}/all`);
// 用 await 關鍵字 等待資料回傳完成

if (!res.ok) throw new Error(`SOMETHING WENT WRONG! (${res.status})`);
// 如果沒有回傳成功 則丟出錯誤 讓 catch 可以接住並報錯

const data = await res.json();
// 用 await 關鍵字 解析回傳的資料

if (!data) throw new Error("DATA IS NOT FOUND!");
// 如果沒有資料 則丟出錯誤 讓 catch 可以接住並報錯

displayCountries(data);
// 將資料寫成 DOM 並且渲染
} catch (err) {
console.error(err);
}
};

其他端點的寫法也差不多,只是要綁在不同的事件監聽器上。


黑夜模式還沒有寫好,只要跳轉其他畫面,就會恢復原狀,所以這部分會進一步優化,只是要等我睡飽(躺平)


完成頁面 ▶ What's the country

Solution ▶ Frontend Mentor - What's the country

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.