TIL 38 | 아이디 검색 기능 구현 - Array.filter(), z-index

meow·2020년 8월 28일
1

JavaScript

목록 보기
25/46
post-thumbnail

인스타그램의 search input을 구현하는 작업이었다. 값을 입력할때마다 그 값을 포함하는 배열을 새로 만들어 리스트로 보여주는 형식이다. 아직 서버에서 데이터를 가져오는 방법은 모르기 때문에, 아이디와 닉네임, 사진이 담긴 배열을 자바스크립트에서 선언하여 작업했다.

To-Dos

추가 구현 사항을 진행하기 전 실제 인스타그램 search input을 분석해보았다.

  • 인풋에 타이핑이 될때마다 새로운 배열을 노출시킨다.
  • 인풋에 value가 있을 때만 컨테이너가 나타난다.
  • input의 value로 시작되는 아이디 뿐만 아니라 중간에 value가 포함된 아이디도 노출을 시킨다.
  • 컨테이너를 넘어가는 배열은 overflow: auto로 스크롤하면 보이게 된다. 컨테이너는 최대 높이값이 지정되어 있다.

JavaScript 코드

계정 데이터 배열 형태

가상의 계정 데이터 배열은 다음과 같이 구성하였다. array 안에 개개인의 user 정보값이 object로 묶인 형태이다.

// 계정 데이터 배열
const userArray = [
                {id: "todayis_wendy",
                nickname: "Wendy",
                picture: "https://#"},
                {id: "wecode_bootcamp",
                nickname: ">wecode | 위코드",
                picture: "https://#"},
                {id: "thisisyourhyung",
                nickname: "JIHYUNG LEE",
                picture: "https://#"},
                ...
                ]   

아이디 검색 전체 코드

Array.filter()

MDN | Array.prototype.filter()

.filter() 메소드는 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다. 어떤 요소도 테스트를 통과하지 못하면 빈 배열을 반환한다. 배열의 모든 요소를 looping 한다는 점에서 .forEach(), .map() 메소드와 유사하다고 볼 수 있다.

예제

function isBigEnough(value) {
  return value >= 10;
}

var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered 는 [12, 130, 44]

코드 분석

matchSearch()

function matchSearch(value) {
    const searchID = searchInput.value;
    return value.indexOf(searchID) != -1;
}

value 인자(계정 데이터 배열의 id value)를 받아서 searchInput의 value가 포함되어 있는지 boolean 형태로 리턴해주는 함수이다.

showFilteredID()

function showFilteredID(id) {
    resultBox.style.display = "flex";
    const filteredUser = document.createElement('li');
    filteredUser.innerHTML = `
        <img class="img-profile" src=${id.picture} alt=${id.id}님의 프로필 사진">
        <div class="profile-text">
            <span class="userID point-span">${id.id}</span>
            <span class="sub-span">${id.nickname}</span>  
        </div>`
    searchList.appendChild(filteredUser);
}

위의 인스타그램 분석에서 나왔듯이 결과 리스트 컨테이너는 search input에 값이 있을때만 등장한다. 이를 위해 결과 리스트가 담길 div 컨테이너에 display 속성을 부여하여, display: none으로 보이지 않았던 컨테이너가 나타나게 만들었다. li element를 생성, 그 안에 받아온 배열의 value 값을 innerHTML로 넣어주고, searchList라는 ul태그 안에 appendChild 해준다.

searchInput.addEventListener()

searchInput.addEventListener('keyup', function() {
    searchList.innerHTML = '';
    resultBox.style.display = "none";
    if (searchInput.value) {
        const filteredID = userArray.filter( x => matchSearch(x.id))
        if (filteredID) {
            filteredID.forEach(function(e) {
                showFilteredID(e)
            })
        }
    }
})

드디어 array.filter() 가 등장한다! searchInput에 keyup 이벤트 발생시, 인풋값이 있는 경우에만 matchSearch() 함수로 필터링 된 새로운 배열인 filteredID가 생성된다. 이렇게 필터링 된 배열은 (배열이 있는 경우에만) showFilteredID() 함수를 거쳐 ul 리스트 안에 들어갈 수 있는 형태로 재구성되는 것이다.

searchInput.addEventListener('focusout', function() {
    resultBox.style.display = "none";
})

인풋에서 포커스아웃 되는 순간 resultBox에 display: none;이 적용된다.

새로 배운 filter 메소드를 사용해볼 수 있어 재미있는 작업이었다. 아이디 검색 기능을 구현하는 자체보다는 인스타그램과 동일한 UI를 만드는게 더 어려웠던 것 같다. 개발자 도구 element 탭으로 인스타그램을 계속 분석했는데 css의 z-index 속성을 새로 알게 되었다.

z-index

MDN | CSS z-index

x축, y축, z축 할때 그 z라고 생각하면 쉽다. 화면은 평평하지만 그 안에서 개체들이 쌓이는 순서를 정해준다고 생각하면 된다. positionstatic 외의 다른 값인 요소에 모두 지정할 수 있으며, 값이 클수록 위로 쌓여 올라간다. 정수만 사용이 가능하다.

디폴트값은 auto이며 이 경우 새로운 쌓인 맥락을 생성하지 않고 부모 요소와 동일한 쌓임 맥락에서의 위치를 갖는다. 자식 요소의 z-index 값은 자기 외의 바깥요소와 비교하지 않는다.

내 CSS 코드

결과 컨테이너 박스의 모양 (말풍선 같은?) 형태를 만들기 위해 z-index 속성을 사용했다.

.ui-little-diamond {
    width: 14px;
    height: 14px;
    padding: 1px;
    position: absolute;
    margin: auto;
    left: 0;
    right: -20px;
    top: 12px;
    transform: rotate(45deg);
    background: #fff;
    content: " ";
    box-shadow: 0 0 5px 1px rgba(0, 0, 0, .1);
    z-index: 1;
}

.upper {
    box-shadow: none;
    z-index: 3;
}

.input-result-container {
    width: 243px;
    max-height: 365px;
    position: absolute;
    top: 18px;
    right: -30px;
    background: #fff;
    border: 1px solid #DBDBDB;
    border-radius: 3px;
    box-shadow: 0 0 5px rgba(0,0,0,.1);
    z-index: 2;
}

결과물

profile
🌙`、、`ヽ`ヽ`、、ヽヽ、`、ヽ`ヽ`ヽヽ` ヽ`、`ヽ`、ヽ``、ヽ`ヽ`、ヽヽ`ヽ、ヽ `ヽ、ヽヽ`ヽ`、``ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ`ヽ`ヽ、ヽ、ヽ`ヽ`ヽ 、ヽ、ヽ、ヽ``、ヽ`、ヽヽ 🚶‍♀ ヽ``ヽ``、ヽ`、

0개의 댓글