Javascript 30 Day06:
Type Ahead
專案目標:
- 呼叫 API 獲取 JSON 資料集
- 建立搜尋字串的功能,該功能要過濾出符合搜尋字串的城市名或州名
- 在畫面上印出搜尋結果以及該城市的人口數
- 在城市名或州名中用黃色標出搜尋字串
實作成果
步驟一:呼叫 API 獲取 JSON 資料集
第一步驟要先呼叫 API 獲取 JSON 資料集。
這個部分我想練習不同於 Wes Bos 的方式,所以使用了 XMLHttpRequest()
來獲取資料。
我的解法
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
let data = [];
let request = new XMLHttpRequest();
request.open('GET', endpoint);
request.responseType = 'json';
request.send();
request.onload = function() {
let result = request.response;
result.forEach(el => {
data.push(el);
});
}
|
Wes Bos 的解法
Wes Bos 的寫法簡潔的多,就是用 fetch
。寫法也很類似 axios 套件的寫法。
但原生 JavaScript 的 fetch
缺點很多,例如不支援逾時、進度處理等等。不過在這個範例中是沒有影響的。
1
2
3
4
5
6
|
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
const cities = [];
fetch(endpoint)
.then(blob => blob.json())
.then(data => cities.push(...data));
|
步驟二:建立搜尋字串的功能,該功能要過濾出符合搜尋字串的城市名或州名
第二步驟主要會用到三個觀念:
- 正則表達式
filter()
過濾出陣列中符合條件的元素
match(regexp)
回傳符合正則表達式的元素
我的解法
1
2
3
4
5
6
|
const searchWord = document.querySelector('.search');
function findMatch(){
const regExp = new RegExp(searchWord.value,'gi');
return data.filter(el=>el.city.match(regExp) || el.state.match(regExp));
}
|
步驟三:在畫面上印出搜尋結果以及該城市的人口數
- 搜尋區綁定
keyup
事件監聽
- 把
findMatch()
搜尋結果賦予到變數 cacheData
- 使用
map()
+ join()
把搜尋結果重組成 HTML 字串樣板
- 人口數(population)使用
toLocaleString()
來呈現樣式,千位數的地方會用 ,
標示
- 使用
innerHTML
把組好的 HTML 內容賦予上去,即可在畫面上渲染出搜尋結果
我的解法
1
2
3
4
5
6
7
8
9
10
|
function render(){
const cacheData = findMatch();
let str = cacheData.map(el=>`<li>
<span class="name">${el.city}, ${el.state}</span>
<span class="population">${parseInt(el.population).toLocaleString()}</span>
</li>`).join('');
result.innerHTML = str;
}
searchWord.addEventListener('keyup', render);
|
Wes Bos 的解法
我的解法和 Wes Bos 最大的差異是 Wes Bos 建立了 numberWithCommas()
這個函式來為城市人口數(population)在千位數的地方用 ,
標示。
但我對正則表達式還很苦手,暫時無法理解 Wes Bos 的寫法,所以這裡就改成用可以達到一樣效果的 toLocaleString()
來取代。
這個方法也是我從 | [ Alex 宅幹嘛 ] 👨💻 深入淺出 Javascript30 快速導覽:Day 6:Type Ahead 這個 Youtube 視頻中學習來的,有興趣的話可以看看 (可以從 55:35 開始看)。
1
2
3
|
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
|
步驟四:在城市名或州名中用黃色標出搜尋字串
在步驟三的基礎上,使用 replace()
方法把符合搜尋結果的字串用 <span class="hl">${this.value}</span>
替代掉。
使之加上 hl
屬性,文字得以黃色背景呈現。
我的解法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function render(){
const cacheData = findMatch();
let str = cacheData.map(el=>{
const regExp = new RegExp(this.value,'gi');
const cityName = el.city.replace(regExp,`<span class="hl">${this.value}</span>`);
const stateName = el.state.replace(regExp,`<span class="hl">${this.value}</span>`);
return `
<li>
<span class="name">${cityName}, ${stateName}</span>
<span class="population">${parseInt(el.population).toLocaleString()}</span>
</li>`
}).join('');
result.innerHTML = str;
}
searchWord.addEventListener('keyup', render);
|
延伸閱讀: