iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
JavaScript

火箭通關JS30系列 第 6

JS30-06-Type Ahead

  • 分享至 

  • xImage
  •  

課程目的:

image.png

這次的內容是,當我們在搜索欄打字母,會篩選出相應的城市名稱,達到搜尋篩選的效果
實做連結

本次功能實作重點:

  • 綁定事件監聽器
  • 抓取城市數據
  • 查找相符的城市或州
  • 將population屬性中的數字格式化為帶逗號的形式
  • 畫面顯示篩選結果

綁定事件監聽器

const suggestions = document.querySelector(".suggestions");
  const search = document.querySelector(".search");

  // 當鍵盤keyup時
  search.addEventListener("keyup", displayMatches);
  search.addEventListener("change", displayMatches);

我們在監聽的時候主要是監聽keyup 以及change 事件

keyup

  • 當用戶在鍵盤上輸入或刪除內容時,keyup 事件都會觸發。
  • 但它不會捕捉到一些非鍵盤的輸入變化,例如:通過右鍵點擊選單進行粘貼、使用鼠標拖動文本進行輸入。

所以我們要額外增加監聽事件changechange能捕捉到通過剪貼板粘貼文本、使用語音輸入、更改選項列表中的值等方式進行的輸入變化,正好可以補齊keyup的缺失。

抓取城市數據

  let cities = [];

  //取得城市的資料
  const endpoint = fetch(
    "https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json"
  );
  endpoint
    .then((res) => res.json())
    .then((data) => {
      cities.push(...data);
    });

我們要透過json文件去抓取我們的資料,要取得endpoint的資料需要利用json() 去讀取並解析數據,當取得後數據會傳遞給下一個 then 方法。 data 是一個包含所有城市和州信息的數組。cities.push(...data) 使用展開運算符(...)將 data 數組中的所有元素逐個插入到 cities 數組中。

查找相符的城市或州

當我們去console.log(cities)時可以看到陣列裡包裹著許多物件資料,把[0]物件展開來看會出現以下的內容:

{city: "New York"
growth_from_2000_to_2013: "4.8%"
latitude: 40.7127837
longitude: -74.0059413
population: "8405837"
rank: "1"
state: "New York"}
 function findMatches(wordToMatch, cities) {

    return cities.filter((place) => {
      const regex = new RegExp(wordToMatch, "gi");
      return place.city.match(regex) || place.state.match(regex);
    });
  }

使用 filter()來篩選符合條件的城市
創建一個正則表達式,參數為 wordToMatch,gi 表示全局搜索且忽略大小寫,
使用 match()來檢查cities每個子元素的屬性city 或 state其一是否與正則表達式匹配

將population屬性中的數字格式化為帶逗號的形式

  function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

這段是用來處理,cities中的population屬性,我們利用正則表達式將一個數字格式化,在數字串中的每個千位位置添加逗點","符號,使字串從1234567轉為1,234,567

畫面顯示篩選結果

 function displayMatches() {
    const matchArray = findMatches(this.value, cities);
    
    const html = matchArray
      .map((place) => {
        // 將城市名和州名中與搜索關鍵字匹配的部分用 <span class="hl"> 包裹起來做出提亮效果
        const regex = new RegExp(this.value, "gi");
        const cityName = place.city.replace(
          regex,
          `<span class="hl">${this.value}</span>`
        );
        const stateName = place.state.replace(
          regex,
          `<span class="hl">${this.value}</span>`
        );
        return `
            <li>
              <span class="name">${cityName}, ${stateName}</span>
              <span class="population">${numberWithCommas(
                place.population //取被篩選過後cities的.population元素
              )}</span>
            </li>
          `;
      })
      .join("");
    suggestions.innerHTML = html;
  }

matchArray 內的findMatches(this.value)為當我們在搜索欄打字時取得的值,帶入函式內便可以比對我們輸入的值 以及cities 是否有對應的城市或州,並且篩選為一個陣列

place.city.replace 找到與place.city對應的regex詞彙並轉換成<span class="hl">${this.value}</span>做出字體提亮效果

suggestions.innerHTML=html 將我們取得的資料顯示在網頁上

最後重點整理 :

  • obj.replace(a,b) replace可以用來尋找arr中與a相應的字串並替換成的內容
  • Fetch API: 使用 fetch() 從遠程服務器請求數據。fetch() 返回一個 Promise,可以通過 .then() 方法鏈式調用來處理響應數據。
  • 正則表達式 (RegExp): 正則表達式被用來進行字符串匹配。在此內容,input輸入的字串被轉換為一個正則表達式,用來篩選城市或州名中是否包含這個搜索詞。 new RegExp(wordToMatch, "gi") 中的 "gi" 表示全局匹配並忽略大小寫。

導讀文件以及學習資源

JS30
[ Alex 宅幹嘛 ] 👨‍💻 深入淺出 Javascript30 快速導覽:Day 6:Type Ahead


上一篇
JS30-05 - Flex Panel Gallery
下一篇
JS30-07 - Array Cardio Day 2
系列文
火箭通關JS3030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言