[JS30] Day06: AJAX Type Ahead
keywords: replace
, match
, fetch
, filter
, 資料過濾
, 資料篩選
利用 Fetch API 來取得資料
使用 fetch
的時候它會先回傳 Promise
給我們,第一個回傳的是一個 readableStream
,我們需要先把它解析成 json
來讀取,在 then
中 return 的內容會到下一個 then
的 callback 中可以使用:
更多關於 Fetch API @ MDN 更多關於 Promise @ PJCHENder Evernote
let cities = [];
const endpoint =
'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
// Step1: Fetch Data
fetch(endpoint)
.then((blob) => blob.json()) // 取得 readableStream,並轉成 json 後 return
.then((data) => {
cities = data; // 把 data 代進去 cities 陣列中
});
console.log(cities); // 這裡會取得不到資料
要注意的是,在上面的程式碼最後,當我們使用 console.log
想要直接看 cities 的內容是,會看到空陣列(未被給 data 的值),這是因為 fetch 裡面的是一個非同步事件,因此console.log
其實在 cities 尚未被賦值(cities = data
)就執行了。
因此,如果你想要先看到 cities 的值的話,記得要寫在 .then
的這個 callback 當中,像是這樣:
更多 JS 非同步處理概念 @ PJCHENder blog
fetch(endpoint)
.then((blob) => blob.json()) // 取得 readableStream,並轉成 json 後 return
.then((data) => {
cities = data; // 把 data 代進去 cities 陣列中
console.log(cities); // 這裡可以取得資料
});
建立正規式
可以利用 new RegExp(regex, flag)
來建立正規式:
- 第一個參數放的是正規式的內容
- 第二個參數是
flag
--g
表示 global search,也就是會去找整份文件,而不是找到就停 --i
表示 case insensitive,也就是不去區分大小寫
let regex = new RegExp(wordToMatch, 'gi');
使用正規式找到內容
使用 String.prototype.match(regexp)
這個方法來判斷給的字串當中是否有符合該 regexp 的內容,有的話會以回傳陣列,沒有的話會回傳 null
。
搭配 Array.prototype.filter
我們就可以根據使用者輸入的內容(wordToMatch)來從 cities 中篩選資料:
function findMatch(wordToMatch, cities) {
return cities.filter((place) => {
/**
* g: global search
* i: case insensitive search
**/
let regex = new RegExp(wordToMatch, 'gi');
return place.city.match(regex) || place.state.match(regex);
});
}
使用正規式取代內容
使用 String.prototype.replace(regex|substr, newSubstr)
來置換內容,這個方法會回傳置換後的新字串,++不會++改變原本的字串:
let regex = new RegExp(e.target.value, 'gi');
let cityNameHighlight = place.city.replace(regex, `<span class="hl">${e.target.value}</span>`);
let stateNameHighlight = place.state.replace(regex, `<span class="hl">${e.target.value}</span>`);
input 事件和 change 事件的差異
這裡我們用 input
事件
input event
會在任何元素值改變的時候被出發(例如每打一個字都會觸發一次)change event
則是會在有元素值改變,且該元素脫離 focus 狀態時才觸發
searchInput.addEventListener('input', (e) => {
displayMatch(e);
});