JS30-06-Type-Ahead

練習 fetch()、filter()、RegExp()正規表達式 的運用

目標

  • 當 searchInput 更新時,即時篩選出結果,並顯示於下方List。
  • 顯示篩選結果時,需新增CSS效果,強調顯示 搜尋的字眼。
  • 將數字顯示成有 千分位 的格式。

實踐步驟

  1. 透過 fetch() 取得 cities的資料

  2. 將 cities的資料 過濾出符合條件的資料

    • filter()
    • RegExp()
    • match()
  3. 優化UI

    • 搜尋字串加顏色
    • 數字新增千分位

成品

[DEMO] | [GitHub]


JS學習紀錄

fetch()

先看下面簡單範例的程式碼,再進而解說

簡單範例
1
2
3
4
5
6
7
8
9
10
11
fetch('https://randomuser.me/api/', {})
.then((response) => {
// 這裡會得到一個 ReadableStream 的物件
console.log(response);
// 可以透過 blob(), json(), text() 轉成可用的資訊
return response.json();
}).then((jsonData) => {
console.log(jsonData);
}).catch((err) => {
console.log('錯誤:', err);
});

說明

fetch 會使用 ES6 的 Promise 作回應

  • then 作為 下一步
  • catch 作為 錯誤回應 (404, 500…)

簡單來說,呼叫完 fetch 後,

  • 若是成功的話,就會走 then,然後 then 可以一直接一直接。
  • 若是失敗的話,就會走 catchcatch 只有一次。

回傳格式(ReadableStream)

Fetch API 的 Response 物件中的 body 屬性提供了一個 ReadableStream 物件,

此階段我們無法直接讀取回傳的資料內容,所以需要再轉一手,才能使用取得的資料。

ReadableStream
- arrayBuffer()
- blob()
- formData()
- json() <=常用
- text() <=常用

最常使用的格式 json()text(),至於 blob() 的話,可用於接收圖片檔案。

RegExp()、match()

在範例中,有要篩選出符合條件的 city 或 state,一開始在字串比對時,
我使用了 String.prototype.includes(),不過此method是有區分大小寫(Case-sensitivity)
所以為了搜尋字眼不區分大小寫的話,就需改用 Regular Expressions 方式。

補充說明

str.match(regexp) 的回傳值

  • 有符合:return 一個Array(包含符合條件的結果),範例
  • 無符合:return null
篩選範例
1
2
3
4
5
6
7
8
9
10
11
12
13
function getMatchData(searchString, searchData){
return searchData.filter( item => {
// 方法1:includes
// 使用此方法有一缺點就是「大小寫需一致」才能符合條件。
// 舉例:資料為 "New York" 時,打 "York",可搜尋的到,但是打 "york",就會搜不到。
// return item.city.includes(searchString) || item.state.includes(searchString)

// 方法2:正規表達式
// RegExp參數說明 → g:Global search 、 i:Case-insensitive search
const regex = new RegExp(searchString, 'gi');
return item.city.match(regex) || item.state.match(regex)
})
}

組字串小技巧 array.join(‘’)

範例中,作者在組HTML字串時,利用 .map() 組合出想要的HTML字串,
不過 .map() 回傳是一個 Array,這時作者在 .map() 後,緊接著加了 .join('')
這樣的話,立馬就將原本是 「Array的資料 轉化成 一個字串」,
取代了以往使用 「字串相加」 的用法。

1
2
3
4
5
6
7
8
9
10
11
12
// 第二版:搜尋字串加顏色 、 數字新增千分位
const html = matchData.map( item => {
const regex = new RegExp(this.value, 'gi');
const cityName = item.city.replace(regex, `<span class="hl">${this.value}</span>`);
const stateName = item.state.replace(regex, `<span class="hl">${this.value}</span>`);

return `
<li>
<span class="name">${cityName}, ${stateName}</span>
<span class="population">${numberWithCommas(item.population)}</span>
</li>`
}).join('')

CSS學習紀錄

List清單之摺疊效果

在範例中,搜尋出來的結果,顯示時會有交叉摺疊效果,作者運用下列元素達成此效果。

  • :nth-child(even):nth-child(odd)
  • transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001);
CSS-交叉摺疊效果
1
2
3
4
5
6
7
8
.suggestions li:nth-child(even) {
transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001);
background: linear-gradient(to bottom, #ffffff 0%,#EFEFEF 100%);
}
.suggestions li:nth-child(odd) {
transform: perspective(100px) rotateX(-3deg) translateY(3px);
background: linear-gradient(to top, #ffffff 0%,#EFEFEF 100%);
}