검색어 자동완성

Goody·2021년 3월 10일
12

JS실습

목록 보기
1/2
post-thumbnail

소개

요즘 웬만한 쇼핑몰이나 포털 사이트에는 전부 검색어 자동완성 기능이 있는 걸 볼 수 있다.
그래서 자동완성 기능을 자바스크립트로 구현해보았다.

네이버, 유튜브 등에서 제공하는 검색어 자동완성 기능.



HTML

HTML은 검색어 입력을 받을 <input> 태그,
그리고 추천 검색어들을 리스트로 담을 <ul> 태그,
마지막으로 ul 자체를 감싸는 <container> 태그를 준비한다.

<input class= "search_input">
<container class = "rel_search">
    <ul class="pop_rel_keywords">
    </ul>
</container>

사실 containerdiv로 해도 상관없긴 한데 좀 더 본연의 역할에 맞는 태그명을 짓기로 했다.



CSS

여기서는 기능 구현에만 초점을 맞출 것이므로 CSS는 거의 건들지 않기로 했다.

.hide {
  display: none !important;	/* 사용자가 아무것도 입력하지 않았을 때 검색창을 숨기는 용도*/
}

.rel_search {
  display:flex;
  flex-direction:column;
  justify-content : space-around;
  border: 1px solid red;
  border-radius: 12px;
 
}

.pop_rel_keywords {
  list-style: none;
  margin-right: 30%;

}

.pop_rel_keywords > li {	/* JS에서 동적으로 li를 생성할 때 적용될 스타일*/
  line-height : 250%
}


JS

  • 우선 웹 페이지 내에서 동적으로 변경할 DOM 객체들을 선택한다.
const ul = document.querySelector(".pop_rel_keywords");
const searchInput = document.querySelector(".search_input");
const relContainer = document.querySelector(".rel_search");

DOM 객체를 선택하는 데에 getElementbyId 등 선택 방법은 많지만 querySelector가 class, id, tag 등 좀 더 포괄적으로 선택할 수 있어서 선택했다.



  • 사용자가 검색어를 입력하는 타자 속도는 컴퓨터의 연산보다 빠르지 않다.
    이를 감안해서 서버와의 통신 비용을 줄이기 위해
    일정 시간을 간격으로 검색창을 검사할 함수를 만든다.
const checkInput = () => {
    const beforeInput = searchInput.value;
    timer(beforeInput);
}

checkInput 이 실행되는 시점에서의 searchInput.valuetimer 가 실행되는 시점에서의 searchInput.valuetimer 함수에 의해 n초 정도 차이가 나게 된다.



  • 0.5 초 정도 여유를 두고 주기적으로 실행되는 함수를 만든다. 0.5초 이후에 검색창을 봤을 때 검색창의 내용이 변했다면 서버로부터 자동완성될 데이터를 불러온다.
const timer = (beforeInput) => {
  setTimeout(() => {

    if(searchInput.value === beforeInput) {
      console.log("입력멈춤");
      loadData(searchInput.value);		// 0.5초 내에 입력창이 변했다면 데이터 로드
      checkInput();
      
    } else {
      console.log("입력변함");
      checkInput();
    }
   
    if(searchInput.value === "") {		// 입력창이 비었다면 추천 검색어 리스트 숨김
      relContainer.classList.add("hide");	
    } else {
      relContainer.classList.remove("hide");
    }
  }, 500);
}

검색창 검사는 주기적으로 실행되어야 하므로, 어느 조건에서든 checkInput 함수가 재귀적으로 다시 실행되도록 했다.



  • 지정한 url 로부터 데이터를 불러와서, li 에 적을 데이터의 프로퍼티를 추출하는 과정이다.
    사용자의 입력에 맞춘 데이터를 가져와야 하므로, url 주소의 쿼리 부분에 매개변수를 넣었다.
const loadData = (input) => {
  const url = `https://completion.amazon.com/... 중략...prefix=${input}&event=onFocusWithSearchT`;
  // 매개변수 input 값에 따라 서버에서 해당 검색어와 연관된 추천검색어가 담긴 데이터가 불러와진다.
  
  if(cache === url) return;	// 이전에 부른 데이터랑 다를 때만 fetch로 데이터를 새로 불러온다.
  else {
 	cache = url;
	fetch(url)
	.then((res) => res.json())
	.then(res => fillSearch(res.suggestions))
  }
}

데이터는 직접 만들기에 무리가 있어서 아마존 웹사이트의 url를 활용했다.
(지식 공유해주신 swing 에게 감사드립니다)



* 마지막으로, 불러온 데이터를 미리 만들어둔 HTML 에 뿌려주기만 하면 된다.
const fillSearch = (suggestArr) => {
  ul.innerHTML = "";
  suggestArr.forEach((el, idx) => {
    const li = document.createElement("li");
    li.innerHTML = el.value;
    ul.appendChild(li);
  }) 
}



실행화면




전체 코드

See the Pen 검색자동완성 by junzero741 (@junzero741) on CodePen.




회고

아직은 데이터를 그냥 불러와서 보여주는 수준인 점이 아쉽다.
진정한 자동완성이 되려면 추천검색어가 띄워진 상태에서 키보드 입력을 받아,
자동으로 검색어를 완성해주는 기능이 추가되어야 할 것 같다.

(개선완료)

또 사용자 입력이 0.5초간 멈췄을 때 데이터를 불러와서 띄워주는 로직이므로,
사용자가 검색어를 입력하다가 계속 멈춰있는 경우에도 데이터를 0.5초마다 불러온다.
이미 불러온 데이터를 또 불러오는 건 네트워크 자원 낭비이므로 뭔가 개선이 필요할 듯 싶다.
(개선완료)

좋았던 점은 아직도 잘 이해가 가지 않는 비동기랑 통성명은 한 느낌..?

0개의 댓글