JS30 Day06
這一課講到了抓API的方式&正規表達式,兩者都是前端必學的重點。


Ajax Type Ahead

完成目標

  • 功能
    • 列出符合關鍵字的項目
  • 畫面
    • 列出符合關鍵字的項目
    • 將關鍵字的部份 mark 起來
    • 顯示該項目的「人口」數



index-START.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Type Ahead 👀</title>
<link rel="stylesheet" href="style.css">
</head>
<body>

<form class="search-form">
<input type="text" class="search" placeholder="City or State">
<ul class="suggestions">
<li>Filter for a city</li>
<li>or a state</li>
</ul>
</form>
<script>
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

</script>
</body>
</html>

index-FINISHED.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Type Ahead 👀</title>
<link rel="stylesheet" href="style.css">
</head>
<body>

<form class="search-form">
<input type="text" class="search" placeholder="City or State">
<ul class="suggestions">
<li>Filter for a city</li>
<li>or a state</li>
</ul>
</form>
<script>
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));

function findMatches(wordToMatch, cities) {
return cities.filter(place => {
// here we need to figure out if the city or state matches what was searched
const regex = new RegExp(wordToMatch, 'gi');
return place.city.match(regex) || place.state.match(regex)
});
}

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

function displayMatches() {
const matchArray = findMatches(this.value, cities);
const html = matchArray.map(place => {
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)}</span>
</li>
`;
}).join('');
suggestions.innerHTML = html;
}

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('change', displayMatches);
searchInput.addEventListener('keyup', displayMatches);

</script>
</body>
</html>



學習筆記


★ fetch()

fetch() 是一個全域的方法,包含了需要 fetch 的網址和對應的屬性設定 ( 例如 method、headers、mode、body…等,最基本的寫法屬性不一定要填 ),執行之後會送出 Request,如果得到回應就會回傳帶有 Response 的 Promise 物件,使用 then 將回傳值傳遞下去。

語法:

1
2
3
4
5
6
fetch('網址')
.then(function(response) {
// 處理 response
}).catch(function(err) {
// 錯誤處理
});

  • fetch 的 request 屬性

    屬性 設定值
    url 第一個參數,一定要填的項目,代表需要 fetch 對象的網址
    method GET、POST、PUT、DELETE、HEAD ( 預設 GET )
    headers 要求相關的 Headers 物件 ( 預設 {} )
    mode cors、no-cors、same-origin、navigate ( 預設 cors )
    referrer no-referrer、client 或某個網址 ( 預設 client )
    credentials omit、same-origin、include ( 預設 omit )
    redirect follow、error、manual ( 預設 manual )
    cache default、no-store、reload、no-cache、force-cache ( 預設 default )
    body 要加到要求中的內容 ( 如果 method 為 GET 或 HEAD 則不設定 )

  • fetch 的 response 屬性

    屬性 設定值
    headers 包含與 response 相關的 Headers 物件
    ok 成功回傳 true,不成功回傳 false
    status 狀態代碼,成功為 200
    statusText 狀態文字,成功為 ok
    type response 的類型,例如 basic、cors…等
    url response 的 url

  • fetch 的 response 方法

    方法 設定值
    json() 返回 Promise,resolves 是 JSON 物件
    text() 返回 Promise,resolves 是 text string
    blob() 返回 Promise,resolves 是 blob ( 非結構化物件資料,例如文字或二進位資料 )
    arrayBuffer() 返回 Promise,resolves 是 ArrayBuffer ( 有多少 bytes )
    formData() 返回 Promise,resolves 是 formData ( 表單資料對應的的 Key 或 Value )
    clone() 建立 Response 的複製物件
    error() 返回 Response 的錯誤物件

詳見這篇文章,寫得很清楚:https://www.oxxostudio.tw/articles/201908/js-fetch.html


★ RegExp()

RegExp() 物件表達正規表達式(regular expression)。在 JavaScript 中,正規表達式也是物件。

語法:

1
new RegExp( pattern , attributes );
  • pattern 是一個字符串,指定了正規表達式的模式;
  • attributes 是一個可選的字符串,包含以下屬性:
    • g:全域匹配(查找所有匹配而非在找到第一個匹配後停止)
    • i:不區分大小寫匹配
    • m:多行匹配

  • 建立正規表達式的兩種方法:

    • 使用正規表達式字面值(regular expression literal),包含兩個 / 字元之間的模式:

      1
      var reg = /ab+c/;

      正規表達式字面值在 script 載入時會被編譯,當正規表達式為定值時,使用此方法可獲得較佳效能。

    • 呼叫 RegExp 物件的建構函式:

      1
      var reg2 = new RegExp('ab+c');

      使用建構子函式供即時編譯正則表達式,當 pattern 會異動、事先未知匹配 pattern、或者從其他地方取得時,建議使用。


  • JavaScript 常見的正規表達式函式

    • RegExp.prototype.test():搜尋字串中是否有符合的部分,回傳 true/false

    • RegExp.prototype.exec():以陣列回傳字串中匹配到的部分,否則回傳 null

    • String.prototype.match():以陣列回傳字串中匹配到的部分,否則回傳 null

      本課中使用的方法。

      範例:

      1
      2
      3
      4
      5
      " chai Chai chaii ".match(/cha\w+/);
      // ["chai", index: 1, input: " chai Chai chaii ", groups: undefined]

      " chai Chai chaii ".match(/cha\w+/gi);
      // ["chai", "Chai", "chaii"]
    • String.prototype.replace():尋找字串中匹配的部分,並取代之。

    • String.prototype.search():尋找字串中是否有符合的部分,有的話回傳 index,否則回傳 -1。 另外,search() 會忽視 g,永遠只能搜尋第一個。

    • String.prototype.split():在字串根據匹配到的項目拆成陣列。

    這裡有更多使用方式:https://www.w3school.com.cn/js/jsref_obj_regexp.asp