JS30 Day 6 筆記


Posted by GL on 2023-05-23

功能

  1. 串接 api 拿到資料,
  2. 在搜尋欄中輸入關鍵字後,下方顯示包含此關鍵字的城市或州名以及其人口數
  3. 顯示時,關鍵字底部要有顏色(#ffc600),人口數後面數來每 3 個數字前加 1 個 comma

Demo

step 1 : 用 Fetch API 取得城市的資料

// api 位置
  const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

  // 建立空陣列 - 準備接 api 傳來的資料
  const cities = []

  // 串接 api -fetch 方法
  fetch(endpoint)
  // 由於 fetch 會回傳 Promise,把第一個回傳解析成 json 格式,讓下一個 callback 中使用:
    .then(blob => blob.json())

    // cities 是 const,無法再賦值,這邊 push() 把資料丟進去, ...data,這邊是用 ES6 的展開運算子,
    .then(data => cities.push(...data))

  // 串接 api - XMLHttpRequest 方法
  // const request = new XMLHttpRequest()
  // request.open('GET', endpoint, true)
  // request.onload = function() {
  //   if (request.status >= 200 && request.status < 400) {
  //     const data = JSON.parse(request.responseText)
  //     cities.push(...data)
  //   } 
  // }
  // request.send()

step 2 : 建立 findMatches 函式,比對城市名或州名裡是否包含關鍵字

// 建立函式 - 比對資料的 city 或 state 是否與關鍵字相符

function findMatches(wordToMatch, cities){ 
  // filter() 篩選符合條件的資料
  return cities.filter( place => {

  // 用 RegExp 建立篩選條件
  const regex = new RegExp(wordToMatch,'gi')

  // 用 match() 比對後,回傳符合篩選條件的城市名或州名
  return place.city.match(regex) || place.city.match(regex)
  })
 }

step 3 : 監聽搜尋欄 input 的值

// 取得 '搜尋欄 input'與 '結果顯示列表'的 DOM,並監聽 input 的有輸入且停止輸入的事件, 事件發生時執行 displayMatches

  const searchInput = document.querySelector('.search')
  const suggestions = document.querySelector('.suggestions')
  searchInput.addEventListener('change',displayMatches)
  searchInput.addEventListener('keyup', displayMatches)

step 4 : 建立 displayMatches 函式,找到與搜尋欄內關鍵字相符的資料並顯示出來


// 建立函式 - 找到與搜尋欄內關鍵字相符合的 city 或 state 名稱,帶入結果顯示的 DOM 元素中
function displayMatches(){
  // 取得搜尋欄 input 內的值
  let inputValue = searchInput.value

  // 查找並回傳與搜尋欄 input 內的值比對後,符合的資料
  let matchArray = findMatches(inputValue, cities)

  // 將每筆資料處理後,傳回 HTML
  let html = matchArray.map(place =>{

    // 設定符合條件為輸入的關鍵字
    let regex = new RegExp(inputValue, 'gi')

    // 把城市名中包含關鍵字的部分加 class = "hl",改變關鍵字的背景色
    let cityName = place.city.replace(regex, `<span class="hl">${inputValue}</span>`)

    // 把州名中包含關鍵字的部分加 class = "hl",改變關鍵字的背景色
    let stateName = place.state.replace(regex, `<span class="hl">${inputValue}</span>`)

    //用 map() 會得到一個新的 array,因為要放入 html,因此用 join('') 將 array 內的每項都用''(空字串) 串起來 innerHTLML 渲染到網頁上
    return `
      <li>
        <span class="city">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCoommas(place.population)}</span>
      </li>
  `
  }).join('') 

  // 再將 html 帶入 suggestion 的 innerHTML 中,渲染在網頁上
  suggestions.innerHTML = html
}

step 5 : 建立 numberWithCoommas 函式,以符合所要求的人口數格式

// 建立函式 - 後面數來每三位數字加一個 comma
function numberWithCoommas(x){
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g,',')
}

CSS

nth-child()

排序為第奇數個的 child : nth-child(odd)
排序為第偶數個的 child : nth-child(even)


RegExp()

建立正規式 new RegExp(regex, flag) 來:

第一個參數是正規式的內容
第二個參數是 flag

  • g 表示 global search,=> 尋找整份文件有包含的,而不是找到就停
  • i 表示 case insensitive =>不區分大小寫

參考資料:


#JS 30







Related Posts

Gradient text animation

Gradient text animation

Day04 你知道 setTimout、setInterval、requestAnimationFrame API 三者的關係嗎

Day04 你知道 setTimout、setInterval、requestAnimationFrame API 三者的關係嗎

Day03 運籌帷幄

Day03 運籌帷幄


Comments