06 - Type Ahead 俗話說的好,一天一蘋果,醫生遠離我
一天一 JS,What the f*ck JavaScript?
small steps every day - 記錄著新手村日記
完成目標
功能
畫面
列出符合關鍵字的項目
將關鍵字的部份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 >
CSS 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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 html { box-sizing : border-box; background : #ffc600 ; font-family : 'helvetica neue' ; font-size : 20px ; font-weight : 200 ; } *, *:before, *:after { box-sizing: inherit; }input { width : 100% ; padding : 20px ; }.search-form { max-width : 400px ; margin : 50px auto; }input .search { margin : 0 ; text-align : center; outline : 0 ; border : 10px solid #F7F7F7 ; width : 120% ; left : -10% ; position : relative; top : 10px ; z-index : 2 ; border-radius : 5px ; font-size : 40px ; box-shadow : 0 0 5px rgba (0 , 0 , 0 , 0.12 ), inset 0 0 2px rgba (0 , 0 , 0 , 0.19 ); }.suggestions { margin : 0 ; padding : 0 ; position : relative; }.suggestions li { background : white; list-style : none; border-bottom : 1px solid #D8D8D8 ; box-shadow : 0 0 10px rgba (0 , 0 , 0 , 0.14 ); margin : 0 ; padding : 20px ; transition : background 0.2s ; display : flex; justify-content : space-between; text-transform : capitalize; }.suggestions li :nth-child (even) { transform : perspective (100px ) rotateX (3deg ) translateY (2px ) scale (1.001 ); background : linear-gradient (to bottom, #ffffff 0% ,#EFEFEF 100% ); }.suggestions li :nth-child (odd) { transform : perspective (100px ) rotateX (-3deg ) translateY (3px ); background : linear-gradient (to top, #ffffff 0% ,#EFEFEF 100% ); }span .population { font-size : 15px ; }.hl { background : #ffc600 ; }
JS - step by step 首先,先來學一下如何抓 Json 檔吧!不知道大家習慣用這種舊式的寫法還是新的 ES6 語法 cities
宣告為 const 並設為空陣列,並再底下將 return 回來的結果 …拆開 push
回來呢?我是比較喜歡舊的下面這種寫法啦w
Using Fetch:https://ubin.io/cz5PZD
1 2 3 4 5 6 7 8 9 10 11 12 <script > const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json' ; let cities = null fetch(endpoint) .then(function (blog ) { return blog.json() }) .then(function (myJson ) { return cities = myJson })</script >
瀏覽器 console 看看有沒有抓到:
使用者在輸入 City or State 放開按鍵的時候,搜尋與Json的資料有哪幾筆符合?這邊我們必須透過正則RegExp 來寫,此外也來批純的方法xd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <script > let cities = null fetch(endpoint) .then(function (blog ) { return blog.json() }) .then(function (myJson ) { return cities = myJson }) document .querySelector('.search' ).addEventListener("keyup" , keyupHandler) function keyupHandler ( ) { }</script >
在 pure function findMatches
中,wordToMatch 與 cities 兩個值不會變動,透過正則將 wordToMatch
丟進來,後面 ‘gi’ 裡的 g 代表全部的意思、i 代表不分大小寫,再回資料結構中有 city || state 回傳值…
RegExp:https://ubin.io/pjvYgJ Pure function:https://ubin.io/RpbKDT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script > document .querySelector('.search' ).addEventListener("keyup" , keyupHandler) function keyupHandler ( ) { const matchArray = findMatches(this .value, cities) console .log(matchArray) } function findMatches (wordToMatch, cities ) { return cities.filter(function (place ) { const regex = new RegExp (wordToMatch, 'gi' ) return place.city.match(regex) || place.state.match(regex) }) }</script >
接著來處理 DOM 的資料,並新增抓到的資料透過來新增HTML 到 Class .suggestions
裡,這邊單純只是做資料的處理,可能會看不懂的地方是,以前用單引號表示字串在 ES6 中換成蝌蚪按鍵的一點符號(這個該叫什麼好呢xd ),另一個為 numberWithCommas
方法中的 toLocaleString()
,在原作者中是用正則去做處理,不過感覺用這個會比較直接…
Number.prototype.toLocaleString():https://reurl.cc/NaXNde
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <script > function keyupHandler ( ) { 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('' ) document .querySelector('.suggestions' ).innerHTML = html } function numberWithCommas (x ) { return x.toLocaleString() }</script >
就大功告成啦!
JS - Final 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 <script > const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json' ; let cities = null fetch(endpoint) .then(function (blog ) { return blog.json() }) .then(function (myJson ) { return cities = myJson }) document .querySelector('.search' ).addEventListener("keyup" , keyupHandler) function keyupHandler ( ) { 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('' ) document .querySelector('.suggestions' ).innerHTML = html } function numberWithCommas (x ) { return x.toLocaleString() } function findMatches (wordToMatch, cities ) { return cities.filter(function (place ) { const regex = new RegExp (wordToMatch, 'gi' ) return place.city.match(regex) || place.state.match(regex) }) }</script >
本刊同步於個人網站:http://chestertang.site/ 本次範例程式碼原作者來源:https://reurl.cc/yynKGl