Please enable Javascript to view the contents

【JS30系列】Day 06:Type Ahead

 ·  ☕ 2 分鐘 · 👀... 閱讀
Type Ahead
Javascript 30 Day06: Type Ahead

Wes Bos 的原始專案:JS30 Day06

專案目標:

  1. 呼叫 API 獲取 JSON 資料集
  2. 建立搜尋字串的功能,該功能要過濾出符合搜尋字串的城市名或州名
  3. 在畫面上印出搜尋結果以及該城市的人口數
  4. 在城市名或州名中用黃色標出搜尋字串

實作成果

步驟一:呼叫 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));


步驟二:建立搜尋字串的功能,該功能要過濾出符合搜尋字串的城市名或州名

第二步驟主要會用到三個觀念:

  1. 正則表達式
  2. filter() 過濾出陣列中符合條件的元素
  3. 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));
}


步驟三:在畫面上印出搜尋結果以及該城市的人口數

  1. 搜尋區綁定 keyup 事件監聽
  2. findMatch() 搜尋結果賦予到變數 cacheData
  3. 使用 map() + join() 把搜尋結果重組成 HTML 字串樣板
  4. 人口數(population)使用 toLocaleString() 來呈現樣式,千位數的地方會用 , 標示
  5. 使用 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);

延伸閱讀:



分享

Sylvia-H
作者
Sylvia-H
Web Developer / F2E 前端筆記

comments powered by Disqus