웹 퍼블리싱 정복반 - 2주차

김민주·2021년 10월 29일
1

코딩꾸미

목록 보기
3/5

01. 실습 준비하기

크롬 개발자 도구를 사용해야 합니다.

  • 1) 전체적인 네이버 웹사이트 구조 살펴보기 https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b76ce6ce-6303-4a25-8eae-d2f2849c6b1e/스크린샷_2021-08-05_오전_2.00.29.png
    • 상단 : 탑 배너, 검색창, Nav Bar
    • 좌측 : 메인 배너, 컨텐츠 영역
    • 우측 : 로그인, 광고 영역
  • 2) visual studio 코드 실행해 실습할 프로젝트 생성하기
    • 바탕 화면에 sparta_web_publish 폴더를 생성해 주세요.
    • vscode 로 헤당 폴더를 open 해 주세요
    • vscode 좌측 창에서 2week 폴더를 생성해 주세요.

02. 검색창 + GNB 구조 살펴보기

이번 실습에서는 되도록이면 네이버에 실제 구현된 구조를 최대한 따를 예정입니다.

  • 3) 검색창 구조 살펴보기 크롬 개발자 도구를 통해 검색창(form#sform)을 찾아보면 다음과 같은 구조로 만들어져 있는것을 확인할 수 있습니다. https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8eea51eb-41a5-4c8a-b2d3-79f20743cb2a/스크린샷_2021-07-28_오후_8.04.58.png 이번 실습에서는 hidden input 은 작성할 필요가 없기에 이를 제외한 나머지를 작성하고 스타일을 입혀야 합니다.
  • 4) Global Nav Bar 구조 살펴보기 크롬 개발자 도구로 div#gnb 를 찾아보면 다음과 같은 구조로 되어있음을 확인할수 있습니다. https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f261800c-4210-4d8b-9d5b-79fef2769056/Untitled.png 검색창보다는 구조가 조금 더 복잡하지만. 좌측은 두개의 ul 로 구성되어 있고 우측엔 #NM_WEATHER 의 아이디를 가진 엘리먼트가 개인별 날씨 정보를 vertical slider 로 보여주고 있습니다.

03. 폼 태그 기본과 실습

폼 태그는 주로 사용자가 입력하는 값을 받아 처리하기 위해 사용됩니다. 현업에서 매우 자주 사용되고 중요하므로 기본 개념을 잘 익혀 두어야 해요.

  • 5) 폼 태그 기본 개념 폼 태그는 사용자로부터 데이터를 입력할 수 있는 범위를 지정할때 사용되며 주로 내부 input 요소들이 배치되어 있습니다. 추가로 이러한 정보들을 입력받아 서버와 통신할수 있지만 이번 실습에서는 사용자로부터 값을 입력받을 수 있는 폼을 만드는것 까지 진행합니다.
    • [코드스니펫] 기본 폼 태그
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="UTF-8" />
        </head>
        <body>
          <form action="#" accept-charset="utf-8" name="information" method="get">
            <fieldset >
              <legend>개인정보</legend>
              <div>이름 : <input type="text" name="name" /></div>
              <div>나이 : <input type="text" name="age" /></div>
            </fieldset>
            <br />
            <fieldset >
              <legend>기타정보</legend>
              <div>취미 : <input type="text" name="hobby" /></div>
              <div>특기 : <input type="text" name="specialty" /></div>
            </fieldset>
          </form>
        </body>
      </html>
  • 6) [코드스니펫] 폼 태그 실습
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
      </head>
      <body>
        <form id="login">
          <div>아이디 : <input type="input" id="username" /></div>
          <div>비밀번호 : <input type="password" id="password" /></div>
          <div>
            <label><input type="checkbox" id="checkbox"/> 아이디 패스워드 저장</label>
          </div>
          <button type="submit">제출</button>
        </form>
    
        <script>
          $('#login').submit(function (event) {
            event.preventDefault();
            var username = $('#username').val();
            var password = $('#password').val();
            var isChecked = !!$('#checkbox:checked').val();
            alert(username + ' / ' + password + ' / ' + isChecked);
          });
        </script>
        
      </body>
    </html>

04. 네이버 검색창 만들기 - 구조 설계

네이버 웹 페이지와 개발자 도구를 띄워 둔 상태에서 보아야 합니다.

  • 7) [코드스니펫] HTML 구조 설계
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <link rel="stylesheet" href="style.css" />
      </head>
    
      <body>
        <div id="search" class="search_area">
          <form id="sform" name="sform" action="https://search.naver.com/search.naver" method="get" role="search">
            <fieldset>
              <legend class="blind">검색</legend>
              <div class="green_window">
                <input
                  id="query"
                  name="query"
                  type="text"
                  maxlength="255"
                  class="input_text"
                  tabindex="1"
                  autocomplete="off"
                  placeholder="검색어를 입력해 주세요."
                />
              </div>
              <button id="search_btn" type="submit" title="검색" tabindex="3" class="btn_submit">
                <span class="blind">검색</span>
                <span class="ico_search_submit"></span>
              </button>
            </fieldset>
          </form>
    
          <div class="autocomplete">
            <a href="#" role="button" id="nautocomplete" tabindex="2" class="btn_arw _btn_arw fold" aria-pressed="true" data-atcmp-element="">
              <span class="blind">자동완성 레이어</span>
              <span class="ico_arr"></span>
            </a>
          </div>
        </div>
      </body>
    </html>

05. 네이버 검색창 만들기 - 스타일링

CSS 선택자는 큰 것부터 작은 순서대로 지정해주어야 정확히 헤당 요소를 선택할수 있어요.

  • 8) [코드스니펫] CSS 스타일 작성
    /* reset */
    body,
    button,
    dd,
    dl,
    dt,
    fieldset,
    form,
    h1,
    h2,
    h3,
    h4,
    h5,
    h6,
    input,
    legend,
    li,
    ol,
    p,
    select,
    table,
    td,
    textarea,
    th,
    ul {
      margin: 0;
      padding: 0;
    }
    
    em {
      font-style: normal;
    }
    
    button,
    input {
      border-radius: 0;
      border: 0;
    }
    
    .search_area .input_text::placeholder {
      color: transparent;
    }
    
    html,
    body {
      display: flex;
      width: 100%;
      height: 100%;
      justify-content: center;
      align-items: center;
      font-size: 10px;
      line-height: 10px;
    }
    
    .blind {
      position: absolute;
      clip: rect(0 0 0 0);
      width: 1px;
      height: 1px;
      margin: -1px;
      overflow: hidden;
    }
    
    fieldset,
    img {
      border: 0;
    }
    
    /* background-image setting */
    .search_area .btn_submit .ico_search_submit,
    .search_area .btn_arw .ico_arr {
      /* 네이버 이미지 사용 */
      /* background-image: url(https://s.pstatic.net/static/www/img/uit/2021/sp_main_57f073.png); */
      /* 로컬 이미지 사용 */
      background-image: url("./sp_main.png");
      background-size: 444px 439px;
    }
    
    /* search_area */
    .search_area {
      position: absolute;
    }
    
    /* form */
    .search_area .green_window {
      position: relative;
      width: 582px;
      height: 52px;
      border: 2px solid #4ae94a;
      border-radius: 2px;
    }
    
    .search_area .input_text {
      width: 444px;
      height: 24px;
      padding: 13px 15px;
      margin: 1px;
      background-color: #fff;
      font-size: 18px;
      line-height: 24px;
      color: #000;
      font-weight: 700;
      outline: 0;
      border-radius: 0;
      border: 0;
    }
    
    .search_area .btn_submit {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      width: 56px;
      background-color: #4ae94a;
      border-radius: 0 2px 2px 0;
      cursor: pointer;
    }
    
    .search_area .btn_submit .ico_search_submit {
      display: inline-block;
      width: 22px;
      height: 22px;
      background-position: -420px -208px;
      background-repeat: no-repeat;
      vertical-align: top;
    }
    
    /* autocomplete */
    .search_area .btn_arw {
      position: absolute;
      top: 0;
      right: 64px;
      bottom: 0;
      width: 22px;
    }
    
    .search_area .btn_arw .ico_arr {
      display: inline-block;
      position: absolute;
      top: 50%;
      left: 50%;
      width: 10px;
      height: 5px;
      background-position: -108px -296px;
      background-repeat: no-repeat;
      vertical-align: top;
      margin: -2px 0 0 -5px;
    }
    
    .search_area .btn_arw.fold .ico_arr {
      display: inline-block;
      width: 10px;
      height: 5px;
      background-position: -96px -296px;
      background-repeat: no-repeat;
      vertical-align: top;
    }
  • 9) 총 완성된 코드 naver_search.zip

06. 네이버 GNB 만들기 - 구조 설계

네이버 GNB 는 가로로 긴 구조로 좌측과 우측이 나뉘어져 있는 점을 유의해야 합니다.

  • 10) [코드스니펫] HTML 구조 설계
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>검색창 하단 네비게이션</title>
        <link rel="stylesheet" href="nav.css" />
    
        <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
      </head>
    
      <body>
        <!-- 검색창 하단 네비게이션 -->
        <!-- ly_open 클래스로 더보기 제어-->
        <div id="gnb">
          <div id="NM_FAVORITE" class="gnb_inner">
            <div class="group_nav">
              <!-- 메일, 카페, 블로그 ... TV -->
              <ul class="list_nav type_fix">
                <li class="nav_item">
                  <a href="https://mail.naver.com/" class="nav" data-clk="svc.mail"><i class="ico_mail"></i>메일</a>
                </li>
                <li class="nav_item">
                  <a href="https://section.cafe.naver.com/" class="nav" data-clk="svc.cafe">카페</a>
                </li>
                <li class="nav_item">
                  <a href="https://section.blog.naver.com/" class="nav" data-clk="svc.blog">블로그</a>
                </li>
                <li class="nav_item">
                  <a href="https://kin.naver.com/" class="nav" data-clk="svc.kin">지식iN</a>
                </li>
                <li class="nav_item">
                  <a href="https://shopping.naver.com/" class="nav shop" data-clk="svc.shopping">
                    <span class="blind">쇼핑</span>
                  </a>
                </li>
                <li class="nav_item">
                  <a href="https://shoppinglive.naver.com/home" class="nav shoplive" data-clk="svc.shoppinglive">
                    <span class="blind">쇼핑LIVE</span>
                  </a>
                </li>
                <li class="nav_item">
                  <a href="https://order.pay.naver.com/home" class="nav" data-clk="svc.pay">Pay</a>
                </li>
                <li class="nav_item">
                  <a href="https://tv.naver.com/" class="nav" data-clk="svc.tvcast"><i class="ico_tv"></i>TV</a>
                </li>
              </ul>
              <!-- 사전, 뉴스 ... 웹툰 -->
              <ul class="list_nav NM_FAVORITE_LIST">
                <li class="nav_item"><a href="https://dict.naver.com/" class="nav" data-clk="svc.dic">사전</a></li>
                <li class="nav_item"><a href="https://news.naver.com/" class="nav" data-clk="svc.news">뉴스</a></li>
                <li class="nav_item"><a href="https://finance.naver.com/" class="nav" data-clk="svc.stock">증권</a></li>
                <li class="nav_item"><a href="https://land.naver.com/" class="nav" data-clk="svc.land">부동산</a></li>
                <li class="nav_item"><a href="https://map.naver.com/" class="nav" data-clk="svc.map">지도</a></li>
                <li class="nav_item"><a href="https://vibe.naver.com/" class="nav" data-clk="svc.vibe">VIBE</a></li>
                <li class="nav_item"><a href="https://book.naver.com/" class="nav" data-clk="svc.book"></a></li>
                <li class="nav_item"><a href="https://comic.naver.com/" class="nav" data-clk="svc.webtoon">웹툰</a></li>
              </ul>
              <!-- 더보기 -->
              <a href="#" role="button" class="btn_more" data-clk="svc.more">더보기</a>
            </div>
            <div id="NM_WEATHER" class="group_weather" data-nm-ui="rolling">
              <div class="eg-flick-viewport">
                <div class="eg-flick-camera">
                  <div class="eg-flick-panel 1">
                    <a data-clk="squ.weat" href="https://weather.naver.com/today/09650107" class="weather_area ico_w02">
                      <div class="current_box"><strong class="current" aria-label="현재기온">35.8°</strong><strong class="state">맑음</strong></div>
                      <div class="degree_box"><span class="min" aria-label="최저기온">25.0°</span><span class="max" aria-label="최고기온">37.0°</span></div>
                      <span class="location">반포동</span>
                    </a>
                  </div>
                  <div class="eg-flick-panel 2">
                    <a data-clk="squ.dust" href="https://weather.naver.com/today/09650107" class="air_area">
                      <ul class="list_air">
                        <li class="air_item">미세<strong class="state state_good">좋음</strong></li>
                        <li class="air_item">초미세<strong class="state state_good">좋음</strong></li>
                      </ul>
                      <span class="location">반포동</span>
                    </a>
                  </div>
                  <div class="eg-flick-panel 3">
                    <a data-clk="squ.dust" href="https://weather.naver.com/today/09650107" class="air_area">
                      <ul class="list_air">
                        <li class="air_item">미세<strong class="state state_good">좋음</strong></li>
                        <li class="air_item">초미세<strong class="state state_good">좋음</strong></li>
                      </ul>
                      <span class="location">반포동</span>
                    </a>
                  </div>
                  <div class="eg-flick-panel 4">
                    <a data-clk="squ.dust" href="https://weather.naver.com/today/09650107" class="air_area">
                      <ul class="list_air">
                        <li class="air_item">미세<strong class="state state_good">좋음</strong></li>
                        <li class="air_item">초미세<strong class="state state_good">좋음</strong></li>
                      </ul>
                      <span class="location">반포동</span>
                    </a>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="ly_service">
            <div class="group_service NM_FAVORITE_ALL_LY">
              <dl class="list_service">
                <dt class="service_title">ㄱ-ㅁ</dt>
                <dd class="service_data"><a href="https://weather.naver.com/" name="weather" data-clk="map.weather">날씨</a></dd>
                <dd class="service_data"><a href="https://new-m.pay.naver.com/mycar/" name="mycar" data-clk="map.mycar">네이버 MYCAR</a></dd>
                <dd class="service_data"><a href="https://game.naver.com/" name="ngame" data-clk="map.ngame">네이버 게임</a></dd>
                <dd class="service_data"><a href="https://booking.naver.com/booked/list" name="booking" data-clk="map.booking">네이버 예약</a></dd>
                <dd class="service_data"><a href="https://contents.premium.naver.com/" name="premium" data-clk="map.premium">네이버 프리미엄콘텐츠</a></dd>
                <dd class="service_data"><a href="http://plus.naver.com" name="plus" data-clk="map.plus">네이버플러스 멤버십</a></dd>
                <dd class="service_data"><a href="https://news.naver.com/" name="news" data-clk="map.news">뉴스</a></dd>
                <dd class="service_data"><a href="https://datalab.naver.com/" name="datalab" data-clk="map.datalab">데이터랩</a></dd>
                <dd class="service_data"><a href="https://memo.naver.com/" name="memo" data-clk="map.memo">메모</a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title">ㅂ-ㅅ</dt>
                <dd class="service_data"><a href="https://band.us/" name="band" data-clk="map.band">밴드</a></dd>
                <dd class="service_data"><a href="https://land.naver.com/" name="land" data-clk="map.land">부동산</a></dd>
                <dd class="service_data"><a href="https://bookmark.naver.com/" name="bookmark" data-clk="map.bookmark">북마크</a></dd>
                <dd class="service_data"><a href="https://software.naver.com/main.nhn" name="software" data-clk="map.software">소프트웨어</a></dd>
                <dd class="service_data"><a href="https://sports.news.naver.com/" name="sports" data-clk="map.sports">스포츠</a></dd>
                <dd class="service_data"><a href="https://series.naver.com/" name="nstore" data-clk="map.nstore">시리즈</a></dd>
                <dd class="service_data"><a href="https://serieson.naver.com/" name="serieson" data-clk="map.serieson">시리즈온</a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title"></dt>
                <dd class="service_data"><a href="https://movie.naver.com/" name="movie" data-clk="map.movie">영화</a></dd>
                <dd class="service_data"><a href="https://audioclip.naver.com/" name="audioclip" data-clk="map.audioclip">오디오클립</a></dd>
                <dd class="service_data"><a href="https://office.naver.com/" name="office" data-clk="map.office">오피스</a></dd>
                <dd class="service_data"><a href="https://whale.naver.com/" name="whale" data-clk="map.whale">웨일</a></dd>
                <dd class="service_data"><a href="https://novel.naver.com/" name="webnovel" data-clk="map.webnovel">웹소설</a></dd>
                <dd class="service_data"><a href="https://comic.naver.com/" name="comic" data-clk="map.webtoon">웹툰</a></dd>
                <dd class="service_data"><a href="https://in.naver.com/" name="influencer" data-clk="map.influencer">인플루언서 검색</a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title">ㅈ-ㅊ</dt>
                <dd class="service_data"><a href="https://auto.naver.com/" name="auto" data-clk="map.auto">자동차</a></dd>
                <dd class="service_data"><a href="https://contact.naver.com/" name="contact" data-clk="map.contact">주소록</a></dd>
                <dd class="service_data"><a href="https://finance.naver.com/" name="stock" data-clk="map.stock">증권</a></dd>
                <dd class="service_data"><a href="https://map.naver.com/" name="map" data-clk="map.map">지도</a></dd>
                <dd class="service_data"><a href="https://terms.naver.com/" name="terms" data-clk="map.terms">지식백과</a></dd>
                <dd class="service_data"><a href="https://book.naver.com/" name="book" data-clk="map.book"></a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title">ㅋ-ㅎ</dt>
                <dd class="service_data"><a href="https://calendar.naver.com/" name="calendar" data-clk="map.calendar">캘린더</a></dd>
                <dd class="service_data"><a href="https://clovadubbing.naver.com/" name="dubbing" data-clk="map.clovadub">클로바더빙</a></dd>
                <dd class="service_data"><a href="https://papago.naver.com/" name="papago" data-clk="map.papago">파파고</a></dd>
                <dd class="service_data"><a href="https://post.naver.com/" name="post" data-clk="map.post">포스트</a></dd>
                <dd class="service_data"><a href="https://academic.naver.com/" name="academic" data-clk="map.academic">학술정보</a></dd>
                <dd class="service_data"><a href="https://beta-flight.naver.com/" name="airticket" data-clk="map.airticket">항공권</a></dd>
                <dd class="service_data"><a href="https://store.naver.com/hotels/main" name="hotel" data-clk="map.hotel">호텔</a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title">A-Z</dt>
                <dd class="service_data"><a href="https://keep.naver.com" name="keep" data-clk="map.keep">Keep</a></dd>
                <dd class="service_data"><a href="https://www.modoo.at" name="modoo" data-clk="map.modoo">modoo!</a></dd>
                <dd class="service_data"><a href="https://mybox.naver.com/" name="ndrive" data-clk="map.ndrive">MYBOX</a></dd>
                <dd class="service_data"><a href="https://me.naver.com/tab/news.nhn" name="myfeed" data-clk="map.mysub">MY구독</a></dd>
                <dd class="service_data"><a href="https://entertain.naver.com/home" name="entertain" data-clk="map.entertain">TV연예</a></dd>
                <dd class="service_data"><a href="https://www.vlive.tv/" name="v" data-clk="map.v">V LIVE</a></dd>
                <dd class="service_data"><a href="https://vibe.naver.com/" name="vibe" data-clk="map.vibe">VIBE</a></dd>
              </dl>
              <dl class="list_service">
                <dt class="service_title">사전</dt>
                <dd class="service_data"><a href="https://dict.naver.com/" name="dic" data-clk="map.dic">사전</a></dd>
                <dd class="service_data"><a href="https://ko.dict.naver.com/" name="krdic" data-clk="map.krdic">국어사전</a></dd>
                <dd class="service_data"><a href="https://endic.naver.com/" name="endic" data-clk="map.endic">영어/영영사전</a></dd>
                <dd class="service_data"><a href="https://ja.dict.naver.com/" name="jpdic" data-clk="map.jpdic">일본어사전</a></dd>
                <dd class="service_data"><a href="https://zh.dict.naver.com/" name="cndic" data-clk="map.cndic">중국어사전</a></dd>
                <dd class="service_data"><a href="https://hanja.dict.naver.com/" name="hanja" data-clk="map.hanja">한자사전</a></dd>
                <dd class="service_data"><a href="https://dict.naver.com/" class="link_dic">사전 더보기</a></dd>
              </dl>
            </div>
          </div>
        </div>
    
        <script src="swiper.js"></script>
        <script src="nav.js"></script>
      </body>
    </html>
  • 11) sparta_swiper.js 다운로드 받기 현재 작업중인 폴더에 이 파일을 위치해 주세요.
    • [코드스니펫] 다운받기 sparta_swiper.js.zip
      https://s3.ap-northeast-2.amazonaws.com/materials.spartacodingclub.kr/web_publish/week01/sparta_swiper.js

07. 네이버 GNB 만들기 - 스타일링

  • 14) [코드스니펫] CSS 스타일 작성
    /* reset */
    body,
    button,
    dd,
    dl,
    dt,
    fieldset,
    form,
    h1,
    h2,
    h3,
    h4,
    h5,
    h6,
    input,
    legend,
    li,
    ol,
    p,
    select,
    table,
    td,
    textarea,
    th,
    ul {
      margin: 0;
      padding: 0;
    }
    
    a {
      color: inherit;
      text-decoration: none;
    }
    
    ol,
    ul {
      list-style: none;
    }
    
    body,
    button,
    input,
    select,
    table,
    textarea {
      font-size: 12px;
      line-height: 16px;
      color: #202020;
      font-family: -apple-system, BlinkMacSystemFont, "Malgun Gothic", "맑은 고딕",
        helvetica, "Apple SD Gothic Neo", sans-serif;
    }
    
    /* gnb center */
    html,
    body {
      width: 100%;
      display: flex;
      justify-content: center;
    }
    
    /* background-image setting */
    #gnb .list_nav .ico_mail,
    #gnb .list_nav .ico_tv,
    #gnb .list_nav .shop:before,
    #gnb .list_nav .shoplive:before,
    #gnb .btn_more:after,
    #gnb .weather_area .max:before,
    #gnb .air_area .state.state_good:before {
      /* 네이버 이미지 사용 */
      /* background-image: url(https://s.pstatic.net/static/www/img/uit/2021/sp_main_57f073.png); */
      /* 로컬 이미지 사용 */
      background-image: url(./sp_main.png);
      -webkit-background-size: 444px 439px;
      background-size: 444px 439px;
      background-repeat: no-repeat;
    }
    
    #gnb .weather_area.ico_w02:before {
      /* 네이버 이미지 사용 */
      /* background-image: url(https://s.pstatic.net/static/www/img/uit/2021/sp_weather_time_5f2bbb.png); */
      /* 로컬 이미지 사용 */
      background-image: url(./sp_weather_time.png);
      -webkit-background-size: 215px 185px;
      background-size: 215px 185px;
      background-repeat: no-repeat;
    }
    
    /* blind 접근성 */
    .blind {
      position: absolute;
      clip: rect(0 0 0 0);
      width: 1px;
      height: 1px;
      margin: -1px;
      overflow: hidden;
    }
    
    /* gnb */
    #gnb {
      position: relative;
      width: 100%;
      -webkit-box-shadow: 0 1px 3px 0 #0000001f;
      box-shadow: 0 1px 3px 0 #0000001f;
    }
    
    #gnb .gnb_inner {
      position: relative;
      width: 1130px;
      padding: 0 30px;
      margin: 0 auto;
    }
    
    /* group_nav */
    #gnb .group_nav {
      position: relative;
      overflow: hidden;
      padding: 11px 270px 11px 0;
    }
    
    /* 더보기 버튼 */
    #gnb .btn_more {
      float: left;
      margin-left: 17px;
      font-size: 13px;
      line-height: 30px;
      color: #202020;
      text-align: right;
    }
    
    #gnb .btn_more:after {
      display: inline-block;
      width: 11px;
      height: 7px;
      background-position: -83px -296px;
      background-repeat: no-repeat;
      vertical-align: top;
      content: "";
      margin-left: 7px;
      vertical-align: 2px;
    }
    
    #gnb.ly_open .group_nav .btn_more {
      color: #0ecd5a;
    }
    
    #gnb.ly_open .group_nav .btn_more:after {
      display: inline-block;
      width: 11px;
      height: 7px;
      background-position: -70px -296px;
      background-repeat: no-repeat;
      vertical-align: top;
      vertical-align: 2px;
    }
    
    /* list_nav type_fix */
    #gnb .list_nav {
      float: left;
      font-size: 15px;
      line-height: 30px;
      font-weight: 700;
      color: #000;
      letter-spacing: -0.3px;
    }
    
    #gnb .list_nav:after {
      content: "";
      display: table;
      table-layout: fixed;
      clear: both;
    }
    
    #gnb .list_nav .nav_item {
      float: left;
    }
    
    #gnb .list_nav .shop,
    #gnb .list_nav .shoplive {
      padding: 5px 0;
    }
    
    #gnb .list_nav .nav_item + .nav_item {
      margin-left: 12px;
    }
    
    #gnb .list_nav .nav {
      display: block;
      text-decoration: none;
    }
    
    #gnb .list_nav.type_fix .nav {
      color: #03c75a;
    }
    
    #gnb .list_nav .ico_mail {
      display: inline-block;
      width: 21px;
      height: 21px;
      background-position: -420px -279px;
      background-repeat: no-repeat;
      vertical-align: top;
      margin: 3px 9px 0 0;
    }
    
    #gnb .list_nav .shop:before {
      display: inline-block;
      width: 24px;
      height: 20px;
      background-position: -420px -232px;
      background-repeat: no-repeat;
      vertical-align: top;
      content: "";
      display: block;
    }
    
    #gnb .list_nav .shoplive:before {
      display: inline-block;
      width: 54px;
      height: 20px;
      background-position: -202px -306px;
      background-repeat: no-repeat;
      vertical-align: top;
      content: "";
      display: block;
    }
    
    /* 사전, 뉴스 ... 웹툰  */
    #gnb .list_nav + .list_nav {
      margin-left: 12px;
    }
    
    #gnb .ly_service {
      position: absolute;
      top: 52px;
      right: 0;
      left: 0;
      display: none;
      padding: 20px 30px 22px;
      background-color: #fff;
      border-top: 1px solid #e4e8eb;
      -webkit-box-shadow: 0 4px 4px 0 rgb(0 0 0 / 12%);
      box-shadow: 0 4px 4px 0 rgb(0 0 0 / 12%);
      z-index: 1;
    }
    
    #gnb.ly_open .ly_service {
      display: block;
    }
    
    #gnb .group_service {
      overflow: hidden;
      display: table;
      width: 1128px;
      margin: 0 auto;
      border: 1px solid #e4e8eb;
      border-width: 0 1px;
      table-layout: fixed;
    }
    
    #gnb .list_service {
      display: table-cell;
      padding: 0 14px 0 15px;
      font-size: 13px;
      line-height: 26px;
      letter-spacing: -0.25px;
    }
    
    #gnb .list_service + .list_service {
      border-left: 1px solid #e4e8eb;
    }
    
    #gnb .list_service .service_title {
      margin-bottom: 3px;
      color: #000;
      font-weight: 700;
    }
    
    #gnb .list_service .service_data {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    
    /* NM_WEATHER (오른쪽 버티컬 swiper)*/
    #gnb .group_weather {
      position: absolute;
      top: 0;
      right: 30px;
      bottom: 0;
      overflow: hidden;
      max-width: 270px;
      height: 52px;
      text-align: right;
    }
    
    /* 날씨 */
    #gnb .weather_area {
      overflow: hidden;
      display: inline-block;
      max-width: 100%;
      padding: 12px 0 11px;
      font-size: 13px;
      line-height: 29px;
      vertical-align: top;
    }
    
    #gnb .weather_area:before {
      content: "";
      float: left;
      margin-right: 9px;
    }
    
    #gnb .weather_area.ico_w02:before {
      display: inline-block;
      width: 29px;
      height: 29px;
      background-position: -155px 0;
      background-repeat: no-repeat;
      vertical-align: top;
    }
    
    #gnb .weather_area .current_box {
      float: left;
    }
    
    #gnb .weather_area .current {
      font-size: 15px;
      vertical-align: top;
    }
    
    #gnb .weather_area .state {
      margin-left: 5px;
    }
    
    #gnb .weather_area .degree_box {
      float: left;
      margin-left: 9px;
    }
    
    #gnb .weather_area .min {
      color: #2586ee;
    }
    
    #gnb .weather_area .max {
      color: #e9564a;
    }
    
    #gnb .weather_area .max:before {
      display: inline-block;
      width: 5px;
      height: 11px;
      background-position: -47px -422px;
      background-repeat: no-repeat;
      vertical-align: top;
      content: "";
      margin: 0 3px;
      vertical-align: -1px;
    }
    
    #gnb .weather_area .location {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      display: block;
      padding-left: 9px;
      font-size: 12px;
      color: grey;
      text-align: right;
    }
    
    /* 대기상태 미세먼지 */
    #gnb .air_area {
      overflow: hidden;
      display: inline-block;
      max-width: 100%;
      padding: 17px 0 16px;
      line-height: 18px;
      white-space: nowrap;
      vertical-align: top;
    }
    
    #gnb .air_area .list_air {
      overflow: hidden;
      float: left;
    }
    
    #gnb .air_area .air_item {
      float: left;
      color: #505050;
    }
    
    #gnb .air_area .air_item + .air_item:before {
      content: "";
      display: inline-block;
      width: 1px;
      height: 12px;
      background-color: #e4e8eb;
      margin: 0 10px;
      vertical-align: -1px;
    }
    
    #gnb .air_area .state {
      margin-left: 7px;
      font-size: 13px;
      color: #202020;
    }
    
    #gnb .air_area .state:before {
      content: "";
      margin-right: 6px;
    }
    
    #gnb .air_area .state.state_good:before {
      display: inline-block;
      width: 18px;
      height: 18px;
      background-position: -327px -306px;
      background-repeat: no-repeat;
      vertical-align: top;
    }
    
    #gnb .air_area .location {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      display: block;
      padding-left: 9px;
      color: grey;
      text-align: right;
    }
    
    /* eg-flick */
    #NM_WEATHER .eg-flick-viewport,
    #NM_WEATHER2 .eg-flick-viewport {
      position: relative;
      z-index: 0;
      overflow: hidden;
      height: 100%;
      touch-action: pan-x;
      user-select: none;
      -webkit-user-drag: none;
    }
    
    #NM_WEATHER .eg-flick-camera,
    #NM_WEATHER2 .eg-flick-camera {
      width: 100%;
      height: 100%;
    }

08. 네이버 GNB 만들기 - 스크립트

  • 15) [코드스니펫] jQuery 작성
    // 변수 선언
    // gnd
    const $gnb = $("#gnb");
    // ly_service
    const isLyService = $(".ly_service");
    // btn_more
    const $btn_more = $("#gnb .btn_more");
    
    // 더보기 버튼 클릭시
    // 더보기 => 접기, 접기 => 더보기 로 텍스트 변경
    // ly_service 영역 보여주기
    $btn_more.on("click", function () {
      const $moreBtn = $(this);
      const btnString = $moreBtn.text();
      if (btnString === "더보기") {
        $moreBtn.text("접기");
      } else {
        $moreBtn.text("더보기");
      }
    
      // ly_open 클래스로 더보기 영역 제어
      // gnb toggle class ly_open
      $gnb.toggleClass("ly_open");
    });
    
    // swpier 함수 실행
    
    swiper("#NM_WEATHER .eg-flick-viewport", {
      mode: "autoVertical",
      delay: 3000,
    });
  • 16) 총 완성된 코드 naver_gnb.zip

09. 2주차 끝 & 숙제 설명

네이버 검색창에서 토글되는 "최근검색어" 창 만들기

키워드를 입력중이거나 화살표 버튼을 눌러 헤당 창을 토글할수 있어야 합니다.

검색어 내역이 없을 때

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e07f7ad7-7d55-495e-b65c-4fa7c40f5590/스크린샷_2021-07-28_오후_9.14.02.png

HW. 2주차 숙제 답안

  • 숙제 - 네이버 최근검색어 내역 만들기
    • [코드스니펫] 전체 코드 숙제 - 네이버 최근검색어 내역을 직접 만들어보기.zip
    • HTML
      <!DOCTYPE html>
      <html lang="en">
      
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <link rel="stylesheet" href="style.css" />
      
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"
          integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
      </head>
      
      <body>
        <!-- 숙제 - 네이버 최근검색어 내역을 직접 만들어보기 -->
        <div id="search" class="search_area">
      
          <form id="sform" name="sform" action="https://search.naver.com/search.naver" method="get" role="search">
            <fieldset>
              <legend class="blind">검색</legend>
              <div class="green_window">
                <input id="query" name="query" type="text" maxlength="255" class="input_text" tabindex="1" autocomplete="off"
                  placeholder="검색어를 입력해 주세요.">
              </div>
              <button id="search_btn" type="submit" title="검색" tabindex="3" class="btn_submit">
                <span class="blind">검색</span>
                <span class="ico_search_submit"></span>
              </button>
            </fieldset>
          </form>
      
          <div class="autocomplete">
            <!-- 자동완성 열린 경우 fold 클래스 추가, 딤드인 경우 dim 추가 -->
            <a href="#" role="button" id="nautocomplete" tabindex="2" class="btn_arw _btn_arw fold" aria-pressed="true"
              data-atcmp-element="">
              <span class="blind">자동완성 레이어</span>
              <span class="ico_arr"></span>
            </a>
          </div>
      
          <div id="autoFrame" class="reatcmp">
            <div class="api_atcmp_wrap">
              <div class="atcmp_fixer _recent_layer" style="display: block;">
                <div class="_recent_header atcmp_header">
                  <strong class="tit">최근검색어</strong>
                  <div class="option">
                    <a role="button" href="#" class="item _delAll" aria-pressed="false">전체삭제</a>
                  </div>
                </div>
                <div class="atcmp_container">
                  <!-- 최근검색 기록 -->
                  <ul class="kwd_lst _recent">
                    <!-- <li class="item _item over" data-rank="1" data-template-type="history" data-keyword="스파르타 코딩클럽 웹 퍼블리싱">
                      <a href="#" class="kwd">
                        <span class="fix">
                          <span class="common_ico_kwd"><i class="imsc ico_search"></i></span>
                          <span>스파르타 코딩클럽 웹 퍼블리싱</span>
                        </span>
                      </a>
                      <span class="etc">
                        <em class="date">07.21.</em>
                        <a href="#" role="button" class="bt_item _del" aria-pressed="false"><i class="imsc ico_del">삭제</i></a>
                      </span>
                    </li>
                    <li class="item _item" data-rank="2" data-template-type="history" data-keyword="스파르타 코딩클럽">
                      <a href="#" class="kwd">
                        <span class="fix">
                          <span class="common_ico_kwd"><i class="imsc ico_search"></i></span>
                          <span>스파르타 코딩클럽</span>
                        </span>
                      </a>
                      <span class="etc">
                        <em class="date">07.21.</em>
                        <a href="#" role="button" class="bt_item _del" aria-pressed="false"><i class="imsc ico_del">삭제</i></a>
                      </span>
                    </li>
                    <li class="item _item" data-rank="3" data-template-type="history" data-keyword="스파르타 코딩">
                      <a href="#" class="kwd">
                        <span class="fix">
                          <span class="common_ico_kwd"><i class="imsc ico_search"></i></span>
                          <span>스파르타 코딩</span>
                        </span>
                      </a>
                      <span class="etc">
                        <em class="date">07.17.</em>
                        <a href="#" role="button" class="bt_item _del" aria-pressed="false"><i class="imsc ico_del">삭제</i></a>
                      </span>
                    </li> -->
                  </ul>
                  <!-- 자동저장 끄기 후에 보여지는 화면-->
                  <div class="kwd_info kwd_off _offMsg" style="display: none;">
                    검색어 저장 기능이 꺼져 있습니다.<br>
                    <span class="kwd_dsc">설정이 초기화 된다면 <a href="https://help.naver.com/support/alias/search/word/word_29.naver" class="kwd_help" data-clk="sly.help" target="_blank">도움말</a>을 확인해주세요.</span>
                  </div>
                  <!-- 전체삭제 후에 보여지는 화면-->
                  <div class="kwd_info kwd_none _recentNone" style="display: none;">최근 검색어 내역이 없습니다.<br><span class="kwd_dsc">설정이 초기화 된다면 <a href="https://help.naver.com/support/alias/search/word/word_29.naver" class="kwd_help" data-clk="sly.help" target="_blank">도움말</a>을 확인해주세요.</span></div>
                </div>
                <div class="atcmp_footer">
                  <span class="side_opt_area">
                    <span class="opt_item">
                      <a href="https://help.naver.com/support/service/main.help?serviceNo=605&amp;categoryNo=1991"
                        data-clk="sly.help" target="_blank">도움말</a>
                    </span>
                  </span>
                  <span class="rside_opt_area">
                    <span class="opt_item">
                      <a href="#" class="close _keywordOnOff">자동저장 끄기</a>
                    </span>
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
      
        <script src="recentSearch.js"></script>
        <script src="script.js"></script>
      </body>
      
      </html>
    • CSS
      /* reset */
      body,
      button,
      dd,
      dl,
      dt,
      fieldset,
      form,
      h1,
      h2,
      h3,
      h4,
      h5,
      h6,
      input,
      legend,
      li,
      ol,
      p,
      select,
      table,
      td,
      textarea,
      th,
      ul {
        margin: 0;
        padding: 0;
      }
      
      em {
        font-style: normal;
      }
      
      button,
      input {
        border-radius: 0;
        border: 0;
      }
      
      .search_area .input_text::placeholder {
        color: transparent;
      }
      
      html,
      body {
        display: flex;
        width: 100%;
        height: 100%;
        justify-content: center;
        align-items: center;
        font-size: 10px;
        line-height: 10px;
      }
      
      .blind {
        position: absolute;
        clip: rect(0 0 0 0);
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
      }
      
      fieldset,
      img {
        border: 0;
      }
      
      /* background-image setting */
      .search_area .btn_submit .ico_search_submit,
      .search_area .btn_arw .ico_arr {
        /* 네이버 이미지 사용 */
        /* background-image: url(https://s.pstatic.net/static/www/img/uit/2021/sp_main_57f073.png); */
        /* 로컬 이미지 사용 */
        background-image: url("./sp_main.png");
        background-size: 444px 439px;
      }
      
      .api_atcmp_wrap .imsc,
      .api_atcmp_wrap .imsc_af:after,
      .api_atcmp_wrap .imsc_bf:before {
        display: inline-block;
        overflow: hidden;
        color: transparent;
        white-space: nowrap;
        vertical-align: top;
        background: url(https://ssl.pstatic.net/sstatic/search/pc/img/sp_autocomplete_4d068feb.png)
          0 0 no-repeat;
        background-size: 290px 274px;
      }
      
      /* search_area */
      .search_area {
        position: absolute;
      }
      
      /* form */
      .search_area .green_window {
        position: relative;
        width: 582px;
        height: 52px;
        border: 2px solid #4ae94a;
        border-radius: 2px;
      }
      
      .search_area .input_text {
        width: 444px;
        height: 24px;
        padding: 13px 15px;
        margin: 1px;
        background-color: #fff;
        font-size: 18px;
        line-height: 24px;
        color: #000;
        font-weight: 700;
        outline: 0;
        border-radius: 0;
        border: 0;
      }
      
      .search_area .btn_submit {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: 56px;
        background-color: #4ae94a;
        border-radius: 0 2px 2px 0;
        cursor: pointer;
      }
      
      .search_area .btn_submit .ico_search_submit {
        display: inline-block;
        width: 22px;
        height: 22px;
        background-position: -420px -208px;
        background-repeat: no-repeat;
        vertical-align: top;
      }
      
      /* autocomplete */
      .search_area .btn_arw {
        position: absolute;
        top: 0;
        right: 64px;
        bottom: 0;
        width: 22px;
      }
      
      .search_area .btn_arw .ico_arr {
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        width: 10px;
        height: 5px;
        background-position: -108px -296px;
        background-repeat: no-repeat;
        vertical-align: top;
        margin: -2px 0 0 -5px;
      }
      
      .search_area .btn_arw.fold .ico_arr {
        display: inline-block;
        width: 10px;
        height: 5px;
        background-position: -96px -296px;
        background-repeat: no-repeat;
        vertical-align: top;
      }
      
      /* 자동완성 레이어 ( reatcmp )*/
      .search_area .reatcmp {
        position: absolute;
        top: 55px;
        left: 0;
        width: 586px;
        z-index: 300;
        display: none;
      }
      
      .api_atcmp_wrap {
        font-family: -apple-system, BlinkMacSystemFont, "Malgun Gothic", "맑은 고딕",
          helvetica, "Apple SD Gothic Neo", "나눔바른고딕 옛한글",
          "NanumBarunGothic YetHangul", sans-serif;
        border: 1px solid #e4e7e8;
        border-top: 0;
        border-radius: 0 0 6px 6px;
        box-shadow: 0 2px 3px 0 #00010312;
        letter-spacing: -0.25px;
        line-height: 1.8rem;
        background-color: #fff;
      }
      
      .api_atcmp_wrap .atcmp_fixer {
        position: relative;
        height: 100%;
        padding-bottom: 40px;
        box-sizing: border-box;
      }
      
      /* atcmp_header _recent_header */
      .api_atcmp_wrap .atcmp_fixer .atcmp_header {
        position: relative;
        margin-bottom: -11px;
        padding: 8px 18px 0;
        font-size: 1.4rem;
        line-height: 3.3rem;
        color: #666;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_header .tit {
        font-weight: 400;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_header .option {
        position: absolute;
        top: 9px;
        right: 18px;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_header .option .item {
        display: inline-block;
        font-size: 1.3rem;
        color: grey;
        vertical-align: top;
      }
      
      /* atcmp_container */
      .api_atcmp_wrap .kwd_lst {
        padding: 12px 0;
      }
      
      .api_atcmp_wrap .kwd_lst .item {
        overflow: hidden;
        position: relative;
        height: 3rem;
        padding: 0 8rem 0 18px;
        box-sizing: border-box;
        font-size: 1.4rem;
        line-height: 3rem;
      }
      
      .api_atcmp_wrap .kwd_lst .item.over {
        background-color: #f9fafb;
      }
      
      .api_atcmp_wrap a {
        text-decoration: none;
      }
      
      .api_atcmp_wrap .kwd_lst .item .kwd {
        display: block;
        position: relative;
        padding-left: 25px;
        color: #202020;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
      
      .api_atcmp_wrap .common_ico_kwd [class*=ico_] {
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        margin: auto;
      }
      
      .api_atcmp_wrap .common_ico_kwd {
        background-color: #d1d7e5;
      }
      
      .api_atcmp_wrap [class*="common_ico_"]:before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        border: 1px solid rgba(0, 0, 0, 0.04);
        border-radius: 50%;
      }
      
      .api_atcmp_wrap [class*="common_ico_"] {
        overflow: hidden;
        position: absolute;
        top: 50%;
        left: 0;
        width: 18px;
        height: 18px;
        margin-top: -9px;
        border-radius: 50%;
      }
      
      .api_atcmp_wrap .common_ico_kwd .ico_search {
        width: 12px;
        height: 12px;
        background-position: -76px -260px;
      }
      
      .api_atcmp_wrap .kwd_lst .item .etc {
        position: absolute;
        top: 0;
        right: 7px;
        width: 8rem;
        text-align: right;
      }
      
      .api_atcmp_wrap .kwd_lst .item .etc .date {
        position: absolute;
        top: 0;
        right: 34px;
        font-size: 1.3rem;
        color: grey;
        letter-spacing: 0;
      }
      
      .api_atcmp_wrap .kwd_lst .item .etc .bt_item {
        display: inline-block;
        width: 32px;
        vertical-align: top;
      }
      
      .api_atcmp_wrap .kwd_lst .item .etc .bt_item .ico_del {
        width: 11px;
        height: 11px;
        background-position: -90px -260px;
        margin-right: 11px;
        vertical-align: -1px;
      }
      
      /* 전체삭제 후에 보여지는 화면 */
      .api_atcmp_wrap .atcmp_fixer .atcmp_container .kwd_info {
        padding: 97px 0 94px;
        font-size: 1.6rem;
        color: #202020;
        text-align: center;
        line-height: 2.5rem;
        letter-spacing: -.5px;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_container .kwd_info .kwd_dsc .kwd_help {
        color: #0c43b7;
      }
      
      /* atcmp_footer */
      .api_atcmp_wrap .atcmp_fixer .atcmp_footer {
        position: absolute;
        right: 0;
        bottom: 0;
        left: 0;
        height: 39px;
        border-top: 1px solid #f1f4f6;
        border-radius: 0 0 6px 6px;
        font-size: 1.3rem;
        line-height: 37px;
        text-align: right;
        background-color: #f9fafb;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_footer .side_opt_area {
        float: left;
        padding-left: 12px;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_footer .rside_opt_area {
        display: inline-block;
        margin-right: 12px;
        vertical-align: top;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_footer .opt_item a {
        display: inline-block;
        padding: 0 6px;
        color: grey;
        vertical-align: top;
      }
      
      .api_atcmp_wrap .atcmp_fixer .atcmp_footer .opt_item a:hover {
        text-decoration: underline;
      }
    • recentSearch.js
      // 변수 선언
      // body 선언
      const $body = $('body')
      // search 선언
      const $search = $('#search');
      // form 선언
      const $sform = $("#sform");
      // input 선언
      const $input = $("input#query");
      // .option 선언
      const $option = $('.option');
      // kwd_lst 선언 (최근 검색어 ul)
      const $kwd_lst = $('.kwd_lst');
      // autoFrame 선언(최근검색어 창)
      const $autoFrame = $('#autoFrame');
      // nautocomplete 선언
      const $nautocomplete = $('#nautocomplete');
      // atcmp_header 선언
      const $atcmp_header= $('.atcmp_header');
      // kwd_info 선언
      const $kwd_info = $('.kwd_info');
      // kwd_off 선언
      const $kwd_off = $('.kwd_info.kwd_off');
      // kwd_none 선언
      const $kwd_none = $('.kwd_info.kwd_none');
      // rside_opt_area (자동저장 끄기)
      const $rside_opt_area = $('.atcmp_footer .rside_opt_area');
      // _keywordOnOff (자동저장 끄기 a태그)
      const $_keywordOnOff = $rside_opt_area.find('._keywordOnOff');
      
      // 자동완성 기능 flag
      let isRecentSearch = true;
      
      // 최근 검색어 와 날짜를 저장하는 배열
      let recentSearchData = [
        // { search: "스파르타 코딩클럽 웹 퍼블리싱", date: "07.23." },
        // { search: "스파르타 코딩클럽", date: "07.20." },
        // { search: "스파르타 코딩", date: "07.10." },
      ];
      
      // 최근 검색어 리스트(li)를 만드는 함수
      const createRecentItem = () => {
        // 초기화
        $kwd_lst.empty();
        recentSearchData.forEach((item, index) => {
          // li 만들기
          $kwd_lst.append(
            `
            <li class="item _item" data-rank="${index + 1}" data-template-type="history" data-keyword="${item.search}">
              <a href="#" class="kwd">
                <span class="fix">
                  <span class="common_ico_kwd"><i class="imsc ico_search"></i></span>
                  <span>${item.search}</span>
                </span>
              </a>
              <span class="etc">
                <em class="date">${item.date}</em>
                <a href="#" role="button" class="bt_item _del" aria-pressed="false"><i class="imsc ico_del">삭제</i></a>
              </span>
            </li>
            `
          )
        })
      }
      
      // 검색창 초기화 함수
      const cleanInput = () => {
        $input.val('');
      }
      
      // 개별삭제
      const deleteSelectedItem = (index) => {
        recentSearchData.splice(index, 1);
      }
      
      // 최근검색어 만 보이게 하는 함수
      const showOlnyRecentItem = () => {
        // recentSearchData.length 가 0 이면
        // 전체삭제 후에 보여지는 화면 만드는 함수 실행
        // 0 이 아니면 atcmp_header 보여주기
        if(recentSearchData.length === 0) {
          const callback = () => {
            // $_keywordOnOff 텍스트 변경
            // 자동저장 켜기 => 자동저장 끄기
            $_keywordOnOff.text('자동저장 끄기');
          }
          showOnlnykwdNone(callback);
          return;
        }else{
          $atcmp_header.show();
        }
        // kwd_info(2개) 모두 숨기기
        $kwd_info.hide();
        // $_keywordOnOff 텍스트 변경
        // 자동저장 켜기 => 자동저장 끄기
        $_keywordOnOff.text('자동저장 끄기');
        // kwd_lst (최근 검색어 ul) 보여주기
        $kwd_lst.show();
      }
      
      // 자동저장 끄기 후에 보여지는 화면 만드는 함수 
      const showOnlnykwdOff = () => {
        // kwd_lst (최근 검색어 ul) 숨기기
        $kwd_lst.hide();
        // atcmp_header 숨기기
        $atcmp_header.hide();
        // kwd_info(2개) 모두 숨기기
        $kwd_info.hide();
        // kwd_off 만 보여주기
        $kwd_off.show();
        // $_keywordOnOff 텍스트 변경
        // 자동저장 끄기 => 자동저장 켜기
        $_keywordOnOff.text('자동저장 켜기');
      }
      
      // 전체삭제 후에 보여지는 화면 만드는 함수 
      const showOnlnykwdNone = (callback) => {
        if(callback){
          callback();
        }
        // atcmp_header 숨기기
        $atcmp_header.hide();
        // kwd_info(2개) 모두 숨기기
        $kwd_info.hide();
        // kwd_none 만 보여주기
        $kwd_none.show();
      }
      
    • script.js
      // load 완료 시 검색창에 foucs 이동
      $(function () {
        $input.focus();
        // recentSearchData 데이터가 없다면 
        // 전체삭제 후에 보여지는 화면 만드는 함수 실행
        if(!recentSearchData.length) showOnlnykwdNone();
      });
      
      // 검색창 클릭시 최근검색어창 토글
      // ico_arr 이미지 변경
      $input.on("click", function () {
        // 자동완성 기능 flag 가 false 면 조기리턴
        if(!isRecentSearch) return;
      
        // 검색기록창 토글 
        $autoFrame.toggle();
      
        // 펼치기, 접기(ico_arr) 이미지 변경
        // nautocomplete 엘리먼트에 fold class toggle
        $nautocomplete.toggleClass('fold');
      });
      
      // search 바깥쪽 클릭시( body 영역에서 search 영역 을 제외한 부분 )
      // 최근검색어 영역 닫기
      $body.on('click', function(e){
        // e.currentTarget == e.target 이 같다면
        // 현재 영역은 serach를 제외한 순수한 body 부분
        if(e.currentTarget == e.target){
          // 최근 검색창 닫기
          $autoFrame.hide();
          // 펼치기, 접기 fold 태그 삭제 
          $nautocomplete.removeClass('fold');
        }
      })
      
      // 펼치기, 접기(nautocomplete) 클릭시
      // 최근 검색창 토글
      // 펼치기, 접기 fold 토글
      $nautocomplete.on('click', function(){
        // 검색기록창 토글 
        $autoFrame.toggle();
        // 펼치기, 접기(ico_arr) 이미지 변경
        // nautocomplete 엘리먼트에 fold class toggle
        $nautocomplete.toggleClass('fold');
      });
      
      // form 기본 동작 막기
      // form submit시 검색어와 날짜 저장하기
      $sform.on("submit", function (e) {
        // form 태그의 기본 이벤트를 막아서
        // 다른 페이지로 리다이렉션 되는 것을 막는다.
        // preventDefault MDN
        // https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault
        e.preventDefault();
      
        // 최근 검색어를 저장한다
        // 현재 input 에 있는 검색어 가져오기
        const query = $input.val();
        // 검색창에 아무것도 입력하지 않고 검색할 경우 조기리턴
        if(!query){ 
          alert('검색어를 입력하세요!')
          return; 
        }
      
        // 자동완성 기능 flag 가 false 면 조기리턴 
        if(!isRecentSearch){
          // 검색창 초기화
          cleanInput();
          // 조기리턴
          return;
        };
      
        // 현재 날짜를 가져온후 format 맞추기
        const date = new Date();
        // 월( 10월 밑으로는 0을 붙여서 저장 )
        const month = ( date.getMonth() + 1 ) < 10 ? '0' + ( date.getMonth() + 1 ) : ( date.getMonth() + 1 );
        // 일( 10일 밑으로는 0을 붙여서 저장 )
        const day = ( date.getDate() ) < 10 ? '0' + ( date.getDate() ) : ( date.getDate() );
      
        // recentSearchData 배열에 넣을 객체 만들기
        const recentSearchItem = {};
        recentSearchItem.search = query;
        recentSearchItem.date = `${month}.${day}.`;
      
        // recentSearchData 배열에 앞에서 부터 recentSearchItem 삽입
        const recentSearch = recentSearchItem;
        recentSearchData.unshift(recentSearch);
      
        // 최근검색어 li 만들기
        createRecentItem();
      
        // 검색창 초기화
        cleanInput();
      
        // 최근 검색 기록 화면만 보여주기
        showOlnyRecentItem();
      
        // 최근 검색창 항상 보여주기
        $autoFrame.show();
      });
      
      // 전체삭제 클릭시 
      // 데이터 초기화
      // 전체삭제 후에 보여지는 화면 보여주기
      $option.on('click', function(){
        const isDelete = confirm("최근검색어를 모두 삭제하시겠습니까?");
      
        // 사용자가 "예" 누를 때만 삭제기능 동작
        if(isDelete){
          // 최근검색어 데이터 초기화
          recentSearchData = [];
          // 최근검색어 다시 그려주기
          createRecentItem();
          // 전체삭제 후에 보여지는 화면 보여주기
          showOnlnykwdNone();
        }
      });
      
      // 개별삭제 클릭시 데이터 해당 데이터 삭제
      // 삭제 버튼(bt_item del)은 동적 생성 되는 엘리먼트라
      // event delegation 을 사용 
      // https://learn.jquery.com/events/event-delegation/
      $search.on('click', '.bt_item._del' , function(){
        // 부모 li data-rank 를 가져와서 -1 을 한후 index로 사용 
        const index = $(this).parents('li').data('rank') - 1;
        // 개별 삭제
        deleteSelectedItem(index);
        // 최근 검색어(li) 다시 만들기
        createRecentItem();
        // recentSearchData 의 length가 0 이면 
        // 전체삭제 후에 보여지는 화면 만드는 함수 실행
        if(recentSearchData.length == 0){
          showOnlnykwdNone();
        }
      });
      
      // 자동저장 끄기 클릭시
      // 자동완성 기능 flag 변수 false로 변경
      $rside_opt_area.on('click', function(){
        const USE = '사용';
        const STOP = '중지';
        const useOrStop = isRecentSearch ? STOP : USE ;
        // confirm 창
        const isAutoComplete = confirm(`최근검색어 저장 기능을 ${useOrStop} 하시겠습니까?`);
        // 취소를 누르면 조기리턴
        if(!isAutoComplete) return;
      
        // isRecentSearch === false ( 자동완성 기능이 꺼져있으면 )
        // 최근검색어 만 보이게 하는 함수 실행
        if(isRecentSearch === false){
          // 전역변수 자동완성 기능 flag 값을 반대로 할당
          isRecentSearch = !isRecentSearch;
          showOlnyRecentItem();
          return;
        }
        // 전역변수 자동완성 기능 flag 값을 반대로 할당
        isRecentSearch = !isRecentSearch;
        // 자동저장 끄기 후에 보여지는 화면 만드는 함수 실행
        showOnlnykwdOff();
      });
profile
뭐든 시작은 좋은 사람

0개의 댓글