跳至主要内容

[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');

線上讀書會-regex 快速入門(承億主講) > 正規式 demo 網站

使用正規式找到內容

使用 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);
});

完成品

Day06 AJAX Type Ahead