[JS] Event delegation을 활용한 smooth scrolling

Minsu Han·2022년 8월 26일

Javascript

목록 보기
2/7

자바스크립트의 이벤트 위임에 대해 찾아보면 다음의 내용을 확인할 수 있다.

링크
캡처링과 버블링을 활용하면 강력한 이벤트 핸들링 패턴인 이벤트 위임(event delegation) 을 구현할 수 있습니다.

이벤트 위임은 비슷한 방식으로 여러 요소를 다뤄야 할 때 사용됩니다. 이벤트 위임을 사용하면 요소마다 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있습니다.

공통 조상에 할당한 핸들러에서 event.target을 이용하면 실제 어디서 이벤트가 발생했는지 알 수 있습니다. 이를 이용해 이벤트를 핸들링합니다.


자바스크립트의 이벤트 위임을 활용하여 navigation bar의 세 링크('.nav__link')를 눌렀을 때 해당하는 페이지 섹션으로 smooth scroll되도록 해 보자

<!-- 네비게이션 바에 위치한 세 링크 -->
<ul class="nav__links">
  <li class="nav__item">
    <a class="nav__link" href="#section--1">Features</a>
  </li>
  <li class="nav__item">
    <a class="nav__link" href="#section--2">Operations</a>
  </li>
  <li class="nav__item">
    <a class="nav__link" href="#section--3">Testimonials</a>
  </li>
  <li class="nav__item">
    <a class="nav__link nav__link--btn btn--show-modal" href="#"
       >Open account</a
      >
  </li>
</ul>
  
<!-- 링크에 해당하는 섹션들 중 하나 -->
<section class="section" id="section--1">
  <div class="section__title">
    <h2 class="section__description">Features</h2>
    <h3 class="section__header">
      Everything you need in a modern bank and more.
    </h3>
  </div>
  ...
  1. 세 링크의 공통 조상에 이벤트리스너를 추가한다.
  2. 공통 조상의 이벤트 객체 e의 e.target은 실제 이벤트가 발생한 위치를 알려준다
  3. e.target이 클래스 nav__link를 포함하는 경우 링크를 클릭한 것이므로 해당 요소의 상대 경로 href (그냥 href가 아닌 getAttribute('href')를 사용해야 절대 경로가 아닌 상대 경로를 얻는다)로 scroll한다.
// 1. Add event listener to common parent element
// 2. Determine what element originated the event
document.querySelector('.nav__links').addEventListener('click', function (e) {
  e.preventDefault();

  // Matching strategy
  // nav__link 외부를 클릭하는 경우를 무시
  if (e.target.classList.contains('nav__link')) {
    const id = e.target.getAttribute('href');
    document.querySelector(id).scrollIntoView({ behavior: 'smooth' });
  }
});

이벤트 위임을 사용하지 않고 세 링크 각각에 이벤트 핸들러를 등록하려면 아래와 같이 작성해야 한다.

document.querySelectorAll('.nav__link').forEach(function (el) {
  el.addEventListener('click', function (e) {
    e.preventDefault();
    const id = this.getAttribute('href');
    console.log(id);
    document.querySelector(id).scrollIntoView({ behavior: 'smooth' });
  });
});
profile
기록하기

0개의 댓글