[2021-05-24] 검색화면(with JSON) 본문

code/Daily Side Project

[2021-05-24] 검색화면(with JSON)

남우p 2021. 5. 24. 11:06

JSON 을 ajax로 불러와서 검색하면을 만드는 프로젝트를 진행하였습니다.

  <div class="container">
    <div class="header">
      <div class="title">패스트푸드점 찾기</div>
      <div class="search">
        <input type="text" id="text-search">
        <button class=btn-search>검색</button>
      </div>
    </div>

    <div class="body">
      <div class="total"></div>
      <div class="list">
        <div id="item-template" class="item">
          <div class="item-no"></div>
          <div class="item-detail">
            <div class="item-name"></div>
            <div class="item-addr"></div>
          </div>
        </div>


      </div>
    </div>
    <div class="paging"></div>
  </div>
@charset "UTF-8";

* {box-sizing:border-box;}
:before,:after {display:none;content:"";}
.container {width:400px;margin:50px auto 80px}
.header {position:relative;background-color: #6a7486;border-radius: 3px;padding: 10px 20px;min-height: 50px;}
.title {display:inline-block;font-size: 16px;color: #fff;vertical-align: middle;font-weight: bold;}
.search {display:inline-block;position:absolute;right:20px;}
.search input {padding:5px;min-height:30px;}
#txt-search {width:300px;height:30px;border:1px solid #ffecd9;border-radius:7px;background-color:#fff6eb;vertical-align:middle;outline:none;text-indent:10px;font-size:17px;}
.btn-search {width:70px;height:30px;background-color: #45484c;margin-left:3px;vertical-align:middle;outline : none;border: 0;cursor:pointer;font-size: 14px;font-weight: bold;color: #fff;}
.total {margin:20px 10px 7px;font-size:13px;color:#bd5a00;}

#item-template {display:none;}
.item {padding:10px 20px;border:1px solid #d2d2d2;border-radius:14px;margin-bottom:10px;}
.item-no {display:inline-block;padding-left:10px;padding-right:10px;font-size:30px;color:#a0a0a0;vertical-align:middle;min-width:17px;}
.item-detail {display:inline-block;margin-left:10px;vertical-align:middle;}
.item-name {font-size:20px;}
.item-addr {font-size:14px;color:#909090;margin-top:2px;}

.paging {text-align:center;}
.paging a {display:inline-block;position:relative;width:20px;height:20px;margin:0 2px;background-color:#444;font-size:14px;text-decoration:none;vertical-align:middle;color:#fff;}
.paging a.current {background-color:#fff;border:1px solid #999;color:#333;}
.paging a:first-child,.paging a:last-child {font-size:0;line-height:0;background-color:#fff;border:1px solid #ddd;}
.paging a:first-child:before,.paging a:last-child:before {display:block;position: absolute;top: 5px;left: 7px;width:7px;height:7px;border-top:1px solid #999;border-left:1px solid #999;transform:rotate(-45deg);}
.paging a:last-child:before {left:auto;right: 8px;transform:rotate(135deg);}
var API_URL = "http://floating-harbor-78336.herokuapp.com/fastfood";
var $searchInput,$searchBtn,$total,$list,$paging;

$(function(){
  $searchInput = $('#text-search');
  $searchBtn = $('.btn-search');
  $total = $('.total');
  $list = $('.list');
  $paging = $('.paging');

  $searchBtn.on('click', function(){
    var searchKwd = $searchInput.val();
    search(1, 10, searchKwd);
  });
  $searchInput.on('keypress', function(e){
    if(e.keyCode === 13){
      $searchBtn.trigger('click');
    }
  })
})
function search(page, perPage, searchKwd){
  $.get(API_URL, {
    page : page,
    perPage : perPage,
    searchKeyword : searchKwd
  }, function(data){
    var list = data.list;
    var total = data.total;
    $total.html('총 ' +total+ '개를 검색했습니다.');
    $list.find($('.item:not(#item-template)')).remove();
    for(var i = 0;i < list.length;i++){
      var $item = $('#item-template').clone().removeAttr('id');
      var elem = list[i];
      $item.find('.item-no').html(i+1);
      $item.find('.item-name').html(elem.name);
      $item.find('.item-addr').html(elem.addr);
      $list.append($item);
    }
    paging(page, perPage, searchKwd, total);

  })
}
function paging(page, perPage, searchKwd, total){
  var setPage = 5;
  var startPage = Math.floor((page - 1) / setPage) * setPage + 1;
  var endPage = startPage + setPage - 1;
  var totalPage = Math.floor(total / setPage);
  if(endPage > totalPage){
    endPage = totalPage;
  }
  $paging.empty();
  var prevPage = page - 1;
  var nextPage = page + 1;
  if(prevPage < 1){
    prevPage = 1;
  }
  if(nextPage > totalPage){
    nextPage = totalPage;
  }
  $prev = $('<a href="javascript:search(' + prevPage + ',' + perPage +', \'' +searchKwd + '\')">이전</a>');
  $paging.append($prev);
  for(var i = startPage;i <= endPage;i++){
    var p = $('<a href="javascript:search(' + i + ',' + perPage +', \'' +searchKwd + '\')">' +i+'</a>');
    if(page === i){
      p.addClass('current');
    }
    $paging.append(p);
  }
  $next = $('<a href="javascript:search(' + nextPage + ',' + perPage +', \'' +searchKwd + '\')">다음</a>');
  $paging.append($next);
}

(code Pen으로 publishing 하고 싶었으나 code Pen에서 async 기능을 block 처리하는 관계로 코드 노출합니다.)

위 코드는 『자바스크립트 프론트엔드 프로젝트 가이드』에 나오는 예제입니다.

 

최근 JSON 사이드 프로젝트를 진행하면서 연관된 내용이라 재미있게 진행했습니다. 특히 paging 부분이 흥미로웠습니다. 친한 개발자 중에 paging을 계속 빼먹는 분이 계시는데, 그 분의 기분이 이해되는 프로젝트 였습니다 ㅎㅎ(책에서도 매우 귀찮은 작업이라고 소개하고 있습니다.) 처음 하는 저는 paging이 굉장히 흥미롭고 재미있는 작업이었는데, 확실히 계속 이 코드를 짜라고 하면 귀찮은 작업이 될 것 같다고 생각했습니다.

 

Ajax를 통해 데이터를 가져오는 작업에서 가장 문제가 되는 부분이 코드 노출이었습니다. 유지보수를 진행하는 측에서는 코드노출이 필요하고, 작업효율 면에서는 DOM에 데이터를 심어서 스크립트 코드로 퍼블리싱 하는 방법이 더 효율적인데, '양쪽 다 만족할 수 있을까?'를 계속 생각했고, .clone()을 통해서 코드노출과 데이터를 넣는 두가지 방법을 모두 만족할 수 있었습니다. 앞으로 유용하게 활용할 예정입니다.

 

해당 책이 초반에는 바닐라 js로 작업하는 방식으로 시작하다가 aync부분에서 jQuery를 사용할 수 밖에 없었는데, XMLHttpRequest 부분이 잘 작동하지 않는 것을 보고 어쩔 수 없는 부분을 실감했습니다.

 

책의 마지막 프로젝트와 함께 돌아오겠습니다~!

Comments