[JavaScript30] ๐Ÿ”Ž06. TYPE AHEAD

์กฐ์ค€ํ˜•ยท2021๋…„ 7์›” 5์ผ
0

JavaScript30

๋ชฉ๋ก ๋ณด๊ธฐ
6/30

๐Ÿ”Ž06 TYPE AHEAD

์›น์—์„œ ์ •๋ณด๋ฅผ ๋ฐ›์•„์™€ Live Search๊ธฐ๋Šฅ์„ ๊ตฌํ˜„

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Type Ahead ๐Ÿ‘€</title>
    <link rel="stylesheet" href="style_JuneHyung.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>
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;
    /*perspective: 20px;*/
}

.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;
}

๐ŸŒ ์ƒˆ๋กœ์•Œ๊ฒŒ๋œ๊ฒƒ๋“ค

๐Ÿ‘‰ text-transform : capitalize

๋Œ€๋ฌธ์ž ๋˜๋Š” ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊พธ๋Š” ์†์„ฑ์œผ๋กœ, uppercase, lowercase๋ฅผ ์ž์ฃผ์ป๋Š”๋ฐ,

capitalize๋Š” ์ฒ˜์Œ ๋ดค๋‹ค.

capitalize : ๋‹จ์–ด์˜ ์ฒซ๋ฒˆ์งธ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌด๋‚ฎ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๐Ÿ‘‰ transform: perspective()

perspective๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด translateZ์˜ ๋ณ€ํ™”๋ฅผ ๋Š๋‚„ ์ˆ˜ ์—†๋‹ค.

perspective๋ฅผ ์‚ฌ์šฉํ•ด ์›๊ธˆ๊ฐ์„ ์ฃผ๋ฉด ์ฐจ์ด๋ฅผ ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค.

์ฐธ๊ณ  :

https://gahyun-web-diary.tistory.com/80

https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Transforms/Using_CSS_transforms

๐Ÿ‘‰ ...

์ „๊ฐœ๊ตฌ๋ฌธ (Spread syntax)

๋‚˜์—ดํ˜• ์ž๋ฃŒ๋ฅผ ์ถ”์ถœํ•˜๊ฑฐ๋‚˜ ์—ฐ๊ฒฐํ•  ๋•Œ ์‚ฌ์šฉ.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด, ๋ณ€์ˆ˜๋ช… ์•ž์— ๋งˆ์นจํ‘œ 3๊ฐœ(...)๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

! ๋ฐฐ์—ด,๊ฐ์ฒด, ํ•จ์ˆ˜ ์ธ์ž ํ‘œํ˜„์‹([],{},()) ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉ.

๐Ÿ‘‰ RegExp

ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด ํ…์ŠคํŠธ๋ฅผ ํŒ๋ณ„ํ•  ๋•Œ ์‚ฌ์šฉ.

RegExp ๊ฐ์ฒด๋Š” ๋ฆฌํ„ฐ๋Ÿด ํ‘œ๊ธฐ๋ฒ•๊ณผ ์ƒ์„ฑ์ž๋กœ์จ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฆฌํ„ฐ๋Ÿด ํ‘œ๊ธฐ๋ฒ•์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๋‘ ๋น—๊ธˆ์œผ๋กœ ๊ฐ์‹ธ์•ผ ํ•˜๋ฉฐ ๋”ฐ์˜ดํ‘œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๋น—๊ธˆ์œผ๋กœ ๊ฐ์‹ธ์ง€ ์•Š์œผ๋‚˜ ๋”ฐ์˜ดํ‘œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
/ab+c/i
new RegExp(/ab+c/, 'i') // ๋ฆฌํ„ฐ๋Ÿด
new RegExp('ab+c', 'i') // ์ƒ์„ฑ์ž

๐Ÿ‘‰ ๋ฌธ๋ฒ•(Syntax)

new` `RegExp(pattern [,flags]) ``// ์ƒ์„ฑ์ž ๋ฐฉ์‹``/pattern/flags ``// ์ •๊ทœํ‘œํ˜„์‹ ๋ฆฌํ„ฐ๋Ÿด 

๐Ÿ‘‰ ์ธ์ž(Parameters)

์ธ์ž๋ช…๋ฐ์ดํ„ฐํ˜•ํ•„์ˆ˜/์˜ต์…˜์„ค๋ช…
patternstringํ•„์ˆ˜์ •๊ทœํ‘œํ˜„์‹
flags์˜ต์…˜g : ํ…์ŠคํŠธ ์ „์ฒด์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž๋ฅผ ์ฐพ์„ ๋•Œ, ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์ฒซ๋ฒˆ์งธ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž๋งŒ ๊ฒ€์ƒ‰
i : ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š”๋‹ค.
m :^(์ฒซ๋ฒˆ์งธ ๋ฌธ์ž)์™€ $(๋งˆ์ง€๋ง‰ ๋ฌธ์ž)๊ฐ€ (\n, \r๋กœ ๊ตฌ๋ถ„๋˜๋Š”) ํ–‰๋‹จ์œ„๋กœ ์ผ์น˜

๐Ÿ‘‰ ์„ค๋ช…(Description)

์ •๊ทœํ‘œํ˜„์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.

  • ๋ฌธ์ž์—ด์—์„œ ํŠน์ • ๋ฌธ์ž์—ด์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
  • ๋ฌธ์ž์—ด์˜ ํŠน์ • ๋ถ€๋ถ„์„ ๋‹ค๋ฅธ ๋ฌธ์ž์—ด๋กœ ๋ณ€๊ฒฝ
CharacterMeaning
\์ด์Šค์ผ€์ดํ•‘(escaping)
^๋ฒ”์œ„, ์‹œ์ž‘ ์ง€์ ,
$๋ฒ”์œ„, ๋๋‚˜๋Š” ์ง€์ 
*์ˆ˜๋Ÿ‰, ์—†๊ฑฐ๋‚˜ ๋” ๋งŽ๋‹ค == {0,}
+์ˆ˜๋Ÿ‰, 1๋ณด๋‹ค ๋งŽ๋‹ค. == {1,}
?์ˆ˜๋Ÿ‰, ์—†๊ฑฐ๋‚˜ ํ•˜๋‚˜์ด๋‹ค.
.์ผ์น˜, ๋ฌธ์ž ํ•˜๋‚˜์™€ ์ผ์น˜
(*x*)์ผ์น˜, x์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ์ฐพ์€ ํ›„์— ์ด์— ์ ‘๊ทผํ• ์ˆ˜ ์žˆ๋„๋ก ํ•จ
x|y์ผ์น˜. x๋‚˜ y์™€ ์ผ์น˜
t{n}์ˆ˜๋Ÿ‰. t์™€ n๋ฒˆ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜
t{n,}์ˆ˜๋Ÿ‰, t์™€ n๋ฒˆ ์ด์ƒ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜
t{n,m}์ˆ˜๋Ÿ‰. t์™€ n๋ฒˆ ์ด์ƒ m๋ฒˆ ์ดํ•˜๋กœ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜
[xyz]์ผ์น˜. xyz์ค‘์— ํ•˜๋‚˜๋ผ๋„ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜

๐Ÿ‘‰ NumberWithCommas()

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

์ •๊ทœ์‹์„ ์ด์šฉํ•˜์—ฌ ์ˆซ์ž๋ฅผ 1000๋‹จ์œ„๋กœ ๋Š์–ด ์ฝค๋งˆ ์‚ฝ์ž….

์ •๊ทœํ‘œํ˜„์‹์—๋Œ€ํ•ด ๊ณต๋ถ€ํ•„์š”.

/\B(?=(\d{3})+(?!\d))/g

\b : ๋‹จ์–ด์˜ ๊ฒฝ๊ณ„(์‹œ์ž‘๊ณผ ๋)๊ฐ€ ์•„๋‹Œ๋ถ€๋ถ„

(\d{3}) :

  • \d : ์ˆซ์ž ๋ฌธ์ž ๋Œ€์‘
  • {n} : ์•ž ํ‘œํ˜„์‹์ด n๋ฒˆ ๋‚˜์˜ค๋Š” ๋ถ€๋ถ„์— ๋Œ€์‘.

=> ์ฆ‰, ์ˆซ์ž๊ฐ€ 3๋ฒˆ

+(?!\d) :

  • + : ์•ž์˜ ํ‘œํ˜„์‹์ด 1ํšŒ ์ด์ƒ ์—ฐ์†์œผ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ๋ถ€๋ถ„๊ณผ ๋Œ€์‘
  • x(?!y) : x๋’ค์— y๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ x์— ์ผ์น˜

=> ์ฆ‰, (?!\d)๋Š” ๋’ค์— ๋”์ด์ƒ ์ˆซ์ž๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ์˜๋ฏธ.

(?= ~~~ ) : ์•ž ๋’ค ์กฐ๊ฑด ๋ชจ๋‘ ๋งŒ์กฑ.

๐ŸŒ ๊ณผ์ •

๐Ÿ‘‰ 1.๋„์‹œ์™€ ์ฃผ์˜ ์ด๋ฆ„๊ณผ ์ธ๊ตฌ์ˆ˜๋ฅผ ๋ฐ›์•„์˜ด.

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

    const cities =[];

    // const porm = fetch(endpoint);
    // console.log(porm);
    
    // fetch(endpoint).then(blob => console.log(blob));
    fetch(endpoint)
    .then(blob => blob.json())
    .then(data=> cities.push(...data));

blob ๊ฒฐ๊ณผํ™”๋ฉด

๊ทธ๋ƒฅ data๋ฅผ cities์— ๋„ฃ์œผ๋ คํ• ๋•Œ error๋ฐœ์ƒ

ํƒ€์ž…์ด ์•ˆ๋งž์•„์„œ ๋ฐœ์ƒํ•˜๋Š”๊ฑฐ ๊ฐ™์•˜์Œ.

fetch(endpoint)
    .then(blob => blob.json())
    .then(data=> cities = data);
Uncaught (in promise) TypeError: Assignment to constant variable. ๋ฐœ์ƒ

๐Ÿ‘‰ 2. ๊ฒ€์ƒ‰ ์‹œ ์ผ์น˜ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์•„๋‚ด๋Š” ํ•จ์ˆ˜

function findMatches(wordToMatch, cities){
        return cities.filter(place => {
            // here we need to figure out if the city on state matches what was searched
            // ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” ์ฃผ์˜ ๋„์‹œ๊ฐ€ ๊ฒ€์ƒ‰๋˜๋Š” ๊ฒƒ๊ณผ ์ผ์น˜ํ•˜๋Š” ์ง€ ์•Œ์•„ ๋‚ด์•ผํ•ฉ๋‹ˆ๋‹ค.

            const regex = new RegExp(wordToMatch, 'gi');
            return place.city.match(regex) || place.state.match(regex);
        })
    }

๋‹จ์–ด๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๋„์‹œ or ์ฃผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ณ€์ˆ˜ regex๋ฅผ ๋งŒ๋“ค๊ณ , ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•ด ๋ฐ˜ํ™˜ํ•˜๋„๋กํ•˜๋Š” findMatchesํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ฌ.

RegExp๋Š” ๊ฒ€์ƒ‰ํ• ๋•Œ ํŒจํ„ด์„ ์„ค์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ๋Š” ์ƒ์„ฑ์ž์ด๊ณ , gi๋Š” ์ „์ฒด์—์„œ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€์•Š๊ณ  ๊ฒ€์ƒ‰ํ•œ๋‹ค๋Š” ์˜๋ฏธ.

g i m ๋ถ™์—ฌ์“ธ ์ˆ˜ ์žˆ๋‚˜๋ด„!

๐Ÿ‘‰ 3. ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๊ฒŒ ํ•˜๋Š” ํ•จ์ˆ˜.

function displayMatches(){
        // console.log(this.value);
        const matchArray = findMatches(this.value, cities);
        // console.log(matchArray);
        const html = matchArray.map(place => {
            
            const regex = new RegExp(this.value, 'gi');
            const cityName = place.city.replace(regex, `<span classs="h1"> ${this.value}</span>`);
            const stateName = place.state.replace(regex, `<span classs="h1"> ${this.value}</span>`);
            return `
                <li>
                    <span class="name">${cityName}, ${stateName}</span>
                    <span class="population">${numberWithCommas(place.population)}</span>
                </li>`
        }).join('');
        suggestions.innerHTML = html;
    }

์ž…๋ ฅํ•œ ๊ฐ’(this.value)๊ณผ ๋ฐ›์•„์˜จ ๋„์‹œ(cities)๋ฅผ ๋งค์น˜ํ•ด์„œ matchArray์— ์ €์žฅ.

const matchArray = findMatches(this.value, cities);

html์— ๊ฒ€์ƒ‰ ํ›„์— ๋ฐฐ์—ด์—์„œ ์ผ์น˜ํ•˜๋Š” ๋‚ด์šฉ์„ ์ฐพ์•„ cityName๊ณผ stateName์— ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰๊ฐ’์ด ๋“ค์–ด๊ฐ„ htmlํƒœ๊ทธ๋กœ ๋Œ€์ฒดํ•˜๋„๋กํ•˜๊ณ , ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ ํƒœ๊ทธ๋ฅผ ๋ฐ˜ํ™˜.

suggenstions์— html๋‚ด์šฉ์„ ์Šคํฌ๋ฆฝํŠธ๋กœ ์‚ฝ์ž…ํ•˜๋Š” ๋ชจ๋“ ๊ณผ์ •์„ displayMatches์— ๋‹ด๋Š”๋‹ค.

๐Ÿ‘‰ 4. ์ˆซ์ž์— 3์ž๋ฆฌ ๋‹จ์œ„๋งˆ๋‹ค ์ฝค๋งˆ(,)

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

์ •๊ทœํ‘œํ˜„์‹์„ ์ด์šฉํ•ด ๋งŒ๋“ฌ.

๐Ÿ‘‰ 5. ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถœ๋ ฅ.

input์— ๊ฐ’์ด ๋ณ€ํ• ๋•Œ์™€ keyup event๊ฐ€ ๋ฐœ์ƒํ• ๋•Œ๋งˆ๋‹ค displayMatches๋ฅผ ๋™์ž‘์‹œํ‚ด.

searchInput.addEventListener('change', displayMatches);
searchInput.addEventListener('keyup', displayMatches);
profile
๊นƒํ—ˆ๋ธŒ : github.com/JuneHyung

0๊ฐœ์˜ ๋Œ“๊ธ€