검색 기능은 실제로 처음 진행해보는 기능이었습니다. 미션 중에서도 추가 미션 7번에 해당하는 기능이었지만, 그 전까지도 절대 수월하지는 않았지만 이전에 구현했었던 경험들을 토대로 구글링을 하며 손수 코드를 짤 수 있었습니다.
다만, 검색 기능은 1도 전혀 감이 잡히지 않아서 멘토분들께 여쭤보려 했습니다만 뭔가 이번에는 밑바닥에서 구글링을 통해서 코드를 짜보고 싶다는 생각이 들었습니다. 그래서 현업에서도 코드를 베끼면서 이해를 하고, 여러 번 본인이 다시 반복해서 사용을 하게 되다보면 내 것이 된다는 멘토분들의 이야기를 듣기로 했습니다.
그래서 위코드 선배 기수인 mia님 블로그 코드를 말 그대로 배껴서 제 코드 맞춰서에 살짝 수정을 진행해서 기능을 구현하였습니다. 아직까지 저의 실력이라고 보기엔 너무나도 어려운 당신인, 검색 기능이지만 이번 기회를 통해서 단순히 구글링하고 코드를 베끼는 작업에서도 분명 얻을 것은 있다는 것이었습니다.
그러나 위에서 언급한 것처럼 이를 내 것으로 만들기 위해서는 이 코드를 반복적으로 직접 써보는 것이므로 다시 한번 블로그로 정리하려 합니다.
HTML
<div class="search-container"> <input class="search-bar" type="text" /> <div class="search-content"> <span class="search">검색</span> <i class="fas fa-search"></i> <i class="fas fa-times-circle"></i> </div> <div class="suggestions-cap"></div> <div class="suggestions-container"> <ul class="suggestions-list"></ul> </div> </div>
CSS
.search-container .suggestions-container { position: absolute; top: 40px; left: -65px; padding-top: 10px; background-color: var(--color-white); box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.1); border-radius: 3px; z-index: 1; }
이번에도 HTML, CSS 자체는 큰 어려움이 없기 때문에 간단하게 구현한 코드만 보여드리겠습니다.
아이디 검색 기능
- 실제 인스타 nav 검색창에 아이디를 입력 시 검색 기능이 실행됩니다.
- 아이디 데이터를 담고 있는 배열을 선언해주세요.
- 검색 창에 텍스트 입력 시 배열의 요소 중 해당 텍스트에 일치하는 아이디만 보일 수 있도록 구현해주세요.
- for 문이 아닌 다른 array method를 사용해 구현해주세요.
위를 준수하여 검색 기능을 만들어보았습니다. 제법 로직이 복잡해서 하나하나씩 살펴보겠습니다. 그리고 검색창 안의 내용은 하드 코딩으로 배열 내 객체 형태로 아래와 같이 정리하였으니 참고 바랍니다.
const accountArray = [
{
id: "wecode_bootcamp",
nickname: ">wecode | 위코드",
image: "/images/wecode.jpeg",
}
]
더 많은 검색 내용을 넣고 싶다면, 배열 안의 객체 형태로 저장하면 되지만 지금의 목표는 검색 기능이므로 형식만 보고 넘어가겠습니다.
const searchFunc = (objId) => {
searchId = searhInput.value;
return objId.indexOf(searchId) !== -1;
}
이름 그대로 검색하는 함수입니다. input에 입력되는 value 값을 변수에 저장합니다. 그리고 매개변수로 입력될 객체의 아이디에 vlaue 값이 있다면 true, 전혀 없다면 false를 반환하게 합니다.
const showFilteredAccount = (account) => {
const containerCap = document.querySelector(".suggestions-cap");
resultContainer.style.display = "block";
containerCap.style.display = "block";
const filteredOne = document.createElement("li");
filteredOne.innerHTML = `<img src=${account.image} alt=${account.id} 사진 />
<div class="suggest-container">
<p class="suggest-username">${account.id}</p>
<p class="suggest-description">${account.nickname}</p>
</div>`;
filteredList.append(filteredOne);
};
복잡해보이지만, 그저 찾은 결과를 li 태그 안으로 넣어주어 화면에 출력되도록 하는 함수입니다. containerCap
은 동기님들의 구원으로 단순한 네모 위에 뾰족한 세모 모양을 만드는 역할입니다.
innerHTML
프로퍼티 값으로 넣어주는 것 중 ${account.id}
나 ${account.image}
는 아시다시피 검색 완료한 결과의 이미지 주소나 아이디 등을 화면에 그려주는 역할을 합니다.
그리고 마지막으로 ul 태그에 filtendOne
이라는 li 태그를 append
해줍니다.
그렇다면, 이제 본격적으로 이벤트를 등록해보겠습니다.
searchInput.addEventListener("keyup", () => {
// 초기화
filteredList.innerHTML = "";
resultContainer.style.display = "none";
// input 값이 있다면,
if (searchInput.value) {
const filteredAccount = accountArray.filter((x) => searchFunc(x.id));
// filteredAccout 배열이 있다면,
if (filteredAccount) {
filteredAccount.forEach((acc) => showFilteredAccount(acc));
}
}
});
초기화하는 부분은 다 아시는 부분일테니 넘어가겠습니다. 인풋에 밸류가 있다면, 하드코딩으로 입력한 배열에 filter
메소드를 진행합니다. 그리고 그 콜백함수 안에 위에 정의해두었던 ((x) => searchFunc(x.id))
함수를 이용해줍니다.
여기서 x는 id, nickname, image 이라는 객체들이고, 거기서 id값만 추려 searchFunc(x.id)와 같이 인자로 입력하여 함수를 실행합니다. 그렇다면 어떻게 될까요?
인풋값과 객체의 id를 비교하여 불리언 값을 반환합니다. filter
는 true인 배열만 반환하므로 검색창에 'e'를 입력했다면, 'e'가 포함된 배열들을 모두 가져오게 되겠네요. 그리고 그 배열을 filteredAccount
이라는 변수에 저장합니다.
'e'가 포함된 모든 배열을 위의 변수에 저장했습니다. 그리고 그 변수에 배열이 있다면, 또 다른 함수가 실행됩니다. 대충 예상이 가시겠지만, 바로 showFilteredAccount()
를 호출하여 화면에 그려주는 일입니다.
위에서 말한 것처럼 filter
로 true인 배열을 반환했고, 이를 배열 메소드인 forEach를 사용하여 화면에 구현하는 함수를 콜백함수로 정의합니다.
// focusout시, 검색 결과 사라지기
searchInput.addEventListener("focusout", () => {
const containerCap = document.querySelector(".suggestions-cap");
resultContainer.style.display = "none";
containerCap.style.display = "none";
});
이제, 검색창에 포커스가 없으면 검색창이 사라지는 코딩을 마지막으로 검색창에 대한 구현을 마쳤습니다. 추가적으로 아래에 검색창에 있는 ❎ 버튼을 클릭하면, 검색 내용 전체가 사라지는 기능을 구현하였습니다. 아래에 코드를 남기니 위 코드를 이해하신 분들이라면 충분히 쉽게 이해가 가실 수 있을 것입니다.
// 검색창 삭제 버튼 기능 구현
searchContent.addEventListener("click", (e) => {
const search = document.querySelector(".search");
const searchIcon = document.querySelector(".fas.fa-search");
const searchDelete = document.querySelector(".fas.fa-times-circle");
if (e.target.className === "fas fa-times-circle focus") {
searchInput.value = "";
search.classList.remove("focus");
searchIcon.classList.remove("focus");
searchDelete.classList.remove("focus");
}
});
검색 기능은 자바스크립트만으로 구현하기에는 저에게는 참으로 어려운 기능이었던 것 같습니다. 솔직히 구글링을 하고, 선배 기수님의 코드를 베끼며 코드를 따라쳤지만 이 방법이 옳은가에 대한 의심이 들었던 것은 사실입니다.
그러나 이러한 방법으로 하면서 느낀 것은 제가 예전 NCS를 공부하는 방식이었다는 것을 깨달았습니다. 매우 생소한 개념을 만났을 때, 자세히 서술된 개념서를 여러 번 읽어도 머리에 전혀 들어오지 않았습니다. 공부에 대한 흥미도 점점 떨어져갔을 때, 이윤규 변호사 공부법이라는 유튜브를 보았습니다.
이러한 상황에서 그는 개념서를 읽기보다 해설지를 보는 공부법을 추천했습니다. 결국, 우리가 해야하는 건 문제 풀이이고, 해설지는 여러 문제에 대한 개념이 학습자가 편히 받아들일 수 있게 짧막한 개념들이 적혀있었습니다.
그의 결론은 이렇게 먼저 해설지를 보면서 문제의 수준을 파악하고, 먼저 짧막한 개념들에 익숙해진 다음 깊숙한 개념들을 다루게 되면 공부가 쉬워질 수 있다는 말이었습니다.
결국, 코딩도 마찬가지일 수 있다고 생각합니다. 누구나에게 공부의 방법은 정해진 것이 없습니다. 다른 사람의 코드를 본 후에 베끼고, 그 개념을 이해하고 반복해서 코드를 쳐보며 나만의 코드로 발전시키게 된다면 어쩌면 이또한 좋은 코딩 공부 방법이 될 수 있다고 생각합니다.
물론, 스스로 구현하려는 노력과 고민도 해보지 않고 구글링을 시작하는 것은 잘못된 방법이라는 것은 모두 아실 것이라 생각하므로 이는 생략하겠습니다. 오늘도 게더 타운에서 만날 동기들과 모각코를 하며 리액트를 공부하러 이만 뛰어가겠습니다. 🏃♂️🏃♂️🏃♂️