完成作品:Type Ahead、程式碼
這天預期的結果是當搜尋時搜尋結果與搜尋框相同的文字會被反白,所以嚴格來說我並沒有達成預期的結果,但還是請大家將就一點看了,之後會再回來修改至完善的 QQ。
首先先列出待辦事項:
由於我還沒學到 fetch
、axios
等方法,所以這裡只能先使用最原始的 XMLHttpRequest
來獲取 API 的資料
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
let data; // 用來儲存 API 的資料
function getData() {
const request = new XMLHttpRequest();
request.open('get', endpoint, true);
request.send(null);
request.addEventListener('readystatechange', (e) => {
// 當資料成功回傳後執行
if(e.target.readyState === 4 && e.target.status === 200) {
data = JSON.parse(request.responseText);
} else if(e.target.readyState === 4) {
console.log(`Failed to fetch data.`);
}
});
}
抓下來的每一項內容格式如下:
{
city: "New York",
growth_from_2000_to_2013: "4.8%",
latitude: 40.7127837,
longitude: -74.0059413,
population: "8405837",
rank: "1",
state: "New York"
}
首先先建立監聽事件,選擇的是之前使用過的 input
,這個事件會隨著刪減文字而觸發事件,而我們要在畫面印出搜尋結果
search.addEventListener('input', printResults);
接著來比較搜尋的內容
const search = document.querySelector('input.search');
let cities = [];
let searchText = '';
function findMatch(e) {
searchText = e.target.value.toLowerCase();
// 檢查資料中是否包含搜尋的關鍵字
cities = data.filter(cur => cur.city.toLowerCase().includes(searchText) || cur.state.toLowerCase().includes(searchText));
}
findMatch
的 e
指的是該搜尋框,比較的方式是透過將搜尋框的內容先轉成小寫,這裡使用 filter
來篩選,其中與資料的 city
與 state
作比較,只要有一項包含搜尋的字串就新增到 cities
這個陣列。
比較完成後我們會得到新的陣列 cities
,來把結果印出來吧!
首先帶入剛剛比較的函式 findMatch
,接下來先把列表 (.suggestions
) 中的內容清空。當然,這裡也可以不用這樣做,之後再直接把列表的 innerHTML
覆蓋即可。
在印出前先做一下判斷,當搜尋框無內容時恢復預設文字;當無相符結果時印出 "Result not found.";當上述兩種情況以外才印出相符的結果
印出結果的方法我用的是剛學到的 insertAjacentHTML
,可以指定插入內容的位置 (beforeend
, beforestart
, afterend
, afterend
),詳情見參考連結
最後除了印出 city、state 外還要印出人口,並加上千位數逗號 (例如 1,500,200)
我找到的方法是使用 Number
內建的方法 toLocaleString()
,使用正規表達式也可以達到一樣效果
const suggestions = document.querySelector('.suggestions');
function printResults(e) {
findMatch(e);
suggestions.innerHTML = '';
if(searchText === '') {
suggestions.insertAdjacentHTML('beforeend',`<li>Filter for a city</li><li>or a state</li>`);
} else if (cities.length === 0) {
suggestions.insertAdjacentHTML('beforeend',`<li>Result not found.</li>`);
} else {
cities.forEach(cur => {
// 為數字加上千位數逗號
const formatedPopulation = Number(cur.population).toLocaleString();
suggestions.insertAdjacentHTML('beforeend',
`
<li>
<span class="name">${cur.city}, ${cur.state}</span>
<span class="population">${formatedPopulation}</span>
</li>
`
);
});
}
}
到這裡就 "大概" 完成了,之後規劃是做出 highlight 功能、使用其他方式獲取 API 資料 (像是 fetch
),以及新增多點搜尋的比較條件。感謝收看~