4. project 필터링 구현

상황

현재 총 project 는 8개다. 이 프로젝트를 아래의 3개 종류로 분류할 수 있다.

  1. front-end

  2. back-end

  3. mobile

종류별로 볼 수 있게 버튼이 위에 만들어져 있으므로, 버튼을 눌렀을 때 알맞은 프로젝트가 나오도록 만들어보자.

순서를 생각해보자

  1. invisible 속성을 만들어서 우리가 원하는 프로젝트가 아니라면 이 속성을 추가해서 css 로 볼 수 없게 만들자.(display: none)

  2. 필터링 버튼을 누른다

    • 필터링 버튼의 html 요소에는 data 속성이 존재하고, 이 속성의 값으로 우리가 원하는 project 을 찾을 수 있게 만든다.

  3. 이후에는 모든 project 를 대상으로 순회를 돌면서 우리가 선택한 프로젝트인지를 검사한다.

    • 맞다면 invisible 속성을 없애주자

    • 우리가 원하는 프로젝트가 아니라면 invisible 속성을 추가해주자.

해결

기본 로직

우리의 index.html 을 보자

<div class="work__categories">
  <button class="category__btn" data-filter="all">
    All <span class="category__count">8</span>
  </button>
  <button class="category__btn" data-filter="front">
    Front <span class="category__count">3</span>
  </button>
  <button class="category__btn" data-filter="back">
    Back <span class="category__count">3</span>
  </button>
  <button class="category__btn" data-filter="mobile">
    Mobile <span class="category__count">2</span>
  </button>
</div>

여기서 버튼을 누르면 data-filter 값을 통해서 all, front 등을 가져와서 아래의 project 에서 data-type 과 비교해서 필터링 한다.

<div class="work__projects">
  <a href="www.naver.com" class="project" target="blank" data-type="front">
    <img src="imgs/projects/project1.png" class="project__img" alt="" />
    <div class="project__description">
      <h3>Project 1</h3>
      <span>first</span>
    </div>
  </a>
  ...
</div>

버튼을 눌러서 filter 값을 얻어오면 projects 를 순회하면서 invisible 속성을 넣어주면 끝!

const targetProject = target.dataset.filter;
projects.forEach(project => {
  if (targetProject == 'all' || project.dataset.type == targetProject) {
    project.classList.remove('invisible');
  } else {
    project.classList.add('invisible');
  }
});

예기치 못한 문제!!!

문제는 버튼을 눌렀을 때 button 내부에 존재하는 span 을 누를 때 발생한다. 즉, 자식 요소를 클릭 했을 때 JS 에서 처리하는 부분이 문제였던것.

이 문제는 모던 자바스크립트 듀토리얼 에서 아주 멋들어지게 해결해준다. 링크의 예시에서 사용한 방법을 보면 아래와 같다.

table.onclick = function(event) {
  let td = event.target.closest('td'); // (1)

  if (!td) return; // (2)

  if (!table.contains(td)) return; // (3)

  highlight(td); // (4)
};

여기서 사용한 closest 는 요소 자신을 포함해서 부모로 올라가면서 인자로 들어온 요소에 해당하는 요소가 있으면 return 하는 메서드다. 즉, 자기 자신이 td 면 바로 자기자신을 리턴하고 아니라면 부모를 통해서 찾아가는것

이걸 우리의 코드에 접목해보면 아래처럼 된다.

workCategory.addEventListener('click', (event) => {
  let target = event.target.closest('.category__btn');
  if (!target) {
    return;
  }
  ...
});

이제 span 을 고의로 눌러도 부모를 찾아가면서 button 을 찾고 리턴한다!!

Last updated