預期結果

Result

透過cities.json取得城市資料清單

在search輸入框輸入關鍵字後

下方要即時顯示符合結果的資料

並把符合字串用黃色背景標記


功能拆解

分為取得cities資料利用regex過濾資料

Fetch API

HTML5提供的API,fetch()回傳promise物件

簡易GET用法如MDN web docs範例

fetch('https://example.com/example.json')
	.then(function(response){
		return response.json();
	})
	.then(function(myjson){
		console.log(myjson)
	})


印出fetch後的response,結果如下

fetch api result

Fetch API Response文件說明,結果資料在body中

但沒有告訴它格式是image? html? json?


method

使用內建的json()將資料轉成json


Spread operator

ES6出現的新特性,把陣列展開成個別的值

要merge成一個新陣列時很好用

let newArr1=['a','b','c']
let newArr2=[1,2,3]
let resultArr=[...newArr1,...newArr2]
// resultArr=['a','b','c',1,2,3]

也可以用concat的寫法

let newArr1=['a','b','c']
let newArr2=[1,2,3]
let resultArr=newArr1.concat(newArr2)

spread處理的複製 屬於shallow copy(copy到物件第一層,第二層仍是參照到記憶體位址)

例如:

let obj ={papa:'peng',mom:'hou',child:{older:'chen',young:'shan'}

let newObj={...obj}

copy result


試著改變原obj的第一層papa值&第二層child.older的值

shallow copy result


回到cities的處理

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))

每筆資料格式如下:

data


filter()

let newArray=array.filter(function(item){
	return condition;
})

逐一驗證item是否符合condition,返回一個新的陣列!


String.match()

參考String.prototype.match()-MDN web docs

str.match(regexp),使用string.match(regex)判斷字串中是否有符合regex的內容,若有找到符合的以陣列回傳結果,若沒有符合的回傳null


Regex

常用flag:

  • i :case-insensitive 大小寫都要!
  • g :looks for all matchs 字串全部搜尋,不會找到一個就停止


建立Regex物件

// long syntax
regexp = new RegExp("pattern", "flags");

// short
regexp = /pattern/; // no flags
regexp = /pattern/gmi; // with flags g,m and i (to be covered soon)

內容摘自javascript.info


回到cities搜尋

  	// find match cities
      function findMatch(word, cities) {
        // 回傳結果(陣列形式)
        return cities.filter((place) => {
          const reg = new RegExp(word, 'gi')
          // filter條件: city or state含有搜尋字串
          return place.city.match(reg) || place.state.match(reg)
        })
      }

最後完成結果

 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))

      // find match cities
      function findMatch(word, cities) {
        // 回傳結果(陣列形式)
        return cities.filter((place) => {
          const reg = new RegExp(word, 'gi')
          // filter條件: city or state含有搜尋字串
          return place.city.match(reg) || place.state.match(reg)
        })
      }

      function displayMatch() {
       // 結果以陣列形式回傳 
       const matchResult=findMatch(this.value,cities);
       // 每一個結果要以li方式呈現
      const html= matchResult.map(place=>{
        // 符合關鍵字以<span>取代
          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">${place.population}<span>
        </li>
         `;
       }).join('')
       suggestions.innerHTML=html;
      }

      const searchs = document.querySelector('.search')
      const suggestions = document.querySelector('.suggestions')

      searchs.addEventListener('change', displayMatch);
      searchs.addEventListener('keyup', displayMatch);