자동 완성에 이미지 넣기

Jaejun Kim·2022년 12월 18일
0

실전다운 실전 프로젝트에서 나는 백엔드였다. 사실 팀원 3명 있었는데 모두 백엔드였다. 왜냐면 그런 팀이었기 때문이다. 프론트는 개차반으로 만들어도 괜찮고 백엔드 기술만 보는..

그중에 가장 프론트다운걸 만들 수 있던 사람이 나였기 때문에 자연스럽게 프론트엔드를 도맡게 되었다. 내가 맡은건 검색도 있었는데, 검색을 만들다보니 자동완성이 그렇게 땡기는 것 아닌가.

그래서 어떻게 간단하게라도 구현을 해보기 위해 jQurey를 뒤지고 다녔다.

간단한 자동 완성을 만드는건 어려운 일이 아니었다. jQuery의 autocomplete를 사용하면 간단하게 자동완성을 구현할 수 있다.

$('#inputBox').autocomplete({ // 자동완성 시작
  source: function (request, response) { // 자동완성에 띄울 데이터를 정하는 함수
    $.ajax({
      type: 'post',
      url: `/search/autocomplete`,
      dataType: 'json',
      data: { value: request.term }, // post를 사용, #inputBox 키워드 === request.term
      success: function (data) {
        response(
          $.map(data, function (item) { // 받아온 데이터는 select 등 다른 프로퍼티에서 사용가능
            return {
              label: item._source.name,
              appid: item._source.appid,
              img_url: item._source.img_url,
            }
          })
        );
      }
    });
  },
  minLength: 2, // 자동완성이 실행되는 최소 글자수
  delay: 350, // 자동완성 딜레이. 없으면 서버터짐
  select: function (event, ui) { // 자동완성 리스트 중 하나를 선택했을 경우 생기는 이벤트
    movePage(ui.item.appid, ui.item.label) 
  }
})

생각보다 금방 만들어버린 자동완성.

근데 아쉬운 점은 autocomplete 기본 기능만을 사용하다보니 확장성이 떨어진다는 것이다.

스팀은 검색결과에 가격과 이미지 또한 넣어주는데, 가격은 모르겠지만 이미지는 꼭 들어가야 한다고 생각하게 되었고, 곧장 코드를 수정하기 시작했다.

express.js에서는 변경할 것이 별로 없었다. 기존 레포지토리 계층 메서드에서 img_url 하나를 더 가져오게 하면 끝이다.

// ElasticSearch JS client.search() option
let option_keywords = {
                "from": 0, "size": 10,
                "_source": ['appid', 'name', 'img_url'],
                "index": "games_data",
                "body": {
                    "query": {
                        "bool": {
                            "must": [
                                {
                                    "match": {
                                        "name.autocomplete": {
                                            "query": value,
                                            "fuzziness": 2 
                                        }
                                    }
                                },
                                { "exists": { "field": "img_url" } }, // 이미지가 있어야함
                                { "exists": { "field": "review_score_desc" } }, // 리뷰가 존재해야함
                            ],
                            "should": [
                                { "prefix": { "name.standard": { "value": value } } },
                                { "match": { "name.standard": value } }, // 노말 검색 up
                                { "match": { "type": 'game' } }, // type이 game이면 + 
                            ]
                        }
                    }
                }
            }

그리고 기존 코드에서 받을 수 있게 끔 해주는 것까지는 완료했다. 근데 여기서 어떻게 무엇을 더 해야할까? 리서치를 해보았다.

검색 결과로는 $(autocomplete) 에 autocomplete를 한번 더 걸어서 temp_html을 붙여넣는 방식이 많았다. 리서치를 한 끝에 블로그 하나를 잡고 시도를 해보기로 했다.

출처: https://wyseburn.tistory.com/entry/jQuery-%EB%B2%84%EC%A0%84-%EB%B3%84-autocomplete-renderItem-%EC%B0%A8%EC%9D%B4

JQuery-ui 버전에 따라 autocomplete 사용법이 다름.

[1.12.0]

jquery 1.7.x 버전 이상을 써야 하고 최신버전 3.2.1 에서도 동작한다.

.autocomplete( "instance" )._renderItem 을 사용할 수 있고

.data("ui-autocomplete")._renderItem 을 사용할 수도 있지만 old style

(대충 아래 방식을 추천한다는 글)

.autocomplete( "instance" )._renderItem = function( ul, item ) {
return $( "<li>" ).append( "<div>" + gubun + S9HL.highlight(label, searched) + "</div>" ).appendTo( ul );
)};

여기서 첫번째 트러블 슈팅이 발생한다.

바로 jQuery의 버전 문제였는데, autocomplete를 사용한 대부분의 자동완성 포스팅은 jQuery, jQuery-ui.js, jQuery-ui.css 모두 1.12.0 버전으로 통일해서 사용하고 있었다.

해당 문법도 적용되면서 지금까지 작성한 코드 중 못쓰는 코드가 발생하지 않도록 jQuery 버전을 조절해야 했는데, 여기서 시간을 상당 시간 소비하였다. 결국 글쓴이가 글을 쓴 시점의 최신 버전인 3.2.1 버전을 적용하니 문제가 생기지 않아 적용하였다.

이후

.data("ui-autocomplete")._renderItem 

.autocomplete( "instance" )._renderItem = function( ul, item ) {
return $( "<li>" ).append( "<div>" + gubun + S9HL.highlight(label, searched) + "</div>" ).appendTo( ul );
)};

둘을 적용해 보았고 두번째 트러블 슈팅이 발생하였다. css를 잘 모르는 나로서는 이것을 어떻게 조합해야 괜찮게 나올지 모르겠던 것. 혼자서 몇 번 시도하다 결국 steam에 들어갔다.

해당 부분의 Element 를 베껴서 일단 그대로 적용해보았다.

.autocomplete("instance")._renderItem = function (ul, item) {
          return $("<li>").append(`
            <a class="match ds_collapse_flag  app_impression_tracked">
              <div class="match_name ">${item.label}</div>
              <div class="match_img">
              <img src="${item.img_url}"></div>
              <div class="match_price">??</div>
            </a>`).appendTo(ul);
        };

결과

처참하게 실패. 쓰지 않는 class를 떼어내고, 필요한 속성들을 집어넣어 사투를 벌인 결과, 어느정도 만족스러운 결과를 낼 수 있었다.

그럼에도 마음에 들지 않는 부분은 여전히 존재했는데, autocomplement로 인해 기본적으로 가지고 있는 기능 중 하나가 계속해서 사라지지 않고 버티던 것. 바로 호버hover 기능이다.

커서를 가져다 댈 때마다 이미지 아래에 살짝 튀어나오는 파란 녀석을 잡는 것을 목표로 해야 했고, 때문에 금방 끝날 줄 알았던 작업이 훨씬 지체되었다.

하다 못해 리액트 수강생 에게도 도움을 청하며 머리를 맞댄 결과, img 크기를 키우고, 이미지가 붙여져있는 방식인 absolute 속성을 이용해서 사진을 움직여 감추기로 했다.

//style
  .match_img {
    position: absolute;
    top: -2px;
    left: -6px;
    border-radius: 2px;
  }

//script
.autocomplete("instance")._renderItem = function (ul, item) {
            return $("<li class='match_li'>").append(
              `<a class="match">
          <div class="match_name">
              ${item.label}
          </div>
          <div class="match_img">
            <img src="${item.img_url}" style="width: 120px; height: 52px;">
          </div>
          <div></div>
        </a>`).appendTo(ul);
          };

결과물

0개의 댓글