[Javascript 30] Day 13 - 스크롤시 이미지 슬라이드 인 효과

이사감·2021년 2월 8일
0

Javascript 30

목록 보기
12/15
post-thumbnail

Day 13 - 스크롤시 이미지 슬라이드 인 효과

스크롤시 이미지가 슬라이드 인 되는 효과를 구현합니다. 특히, debounce 개념과 화면상의 위치를 어떻게 계산할지에 대해 공부합니다.

요구사항

  • 스크롤한 위치가 이미지 영역의 절반 지점이라면 이미지가 슬라이드 인됨
  • 이미지 영역의 절반 지점을 지나면 다시 슬라이드 아웃됨
  • 스크롤을 위->아래 / 아래->위 방향으로 해도 똑같이 구현

TIL

디바운스와 스로틀

디바운스와 스로틀은 모두 이벤트를 제어하는 방법입니다.
강의에서 디바운스를 사용하여 구글링했는데 스로틀과의 비교가 항상 따라다니는듯 함.

참고 자료1 - 제로초
참고 자료2 - web club

디바운스 (Debounce)

이벤트를 그룹화하여 특정 시간이 지난 후 하나의 이벤트만 발생하게 한다. 연이어 호출되는 함수들 중 마지막 함수 또는 제일 처음 함수만 호출되도록 하는 것.

예를들어 브라우저의 크기를 조절할 때 (resize 이벤트) 그 크기를 console.log로 출력하면 실시간으로 변하는 크기 모두가 찍히는 것을 볼 수 있습니다. 문제는 너무 많이 찍혀 과부하가 발생한다는 것입니다. 따라서 이용자가 크기 조절을 완료 했을 때 그때만 크기가 어떻게 되는지 출력하게 만드는 것이 디바운스입니다.

또, 검색창에 검색어를 입력하여 검색을 할 때에도 디바운싱을 이용하여 과부하를 방지할 수 있습니다. 똻 이라는 글자를 입력하는 것을 console.log 해보면 ㄸ, 또, 똬, 똴, 똻 이 전부 찍힙니다. 똻일때만 찍히게끔 하는 것이 디바운스입니다.

//강의에서 사용한 디바운스

      function debounce(func, wait = 20, immediate = true) {
        var timeout;
        return function () {
          var context = this,
            args = arguments;
          var later = function () {
            timeout = null;
            if (!immediate) func.apply(context, args);
          };
          var callNow = immediate && !timeout;
          clearTimeout(timeout);
          timeout = setTimeout(later, wait);
          if (callNow) func.apply(context, args);
        };
      }

스로틀 (Throttle)

이벤트를 일정한 주기마다 발생하도록 한다. 실행 횟수에 제한을 건다. 마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것

예를들어 스로틀의 설정시간으로 1ms를 주면 해당 이벤트는 1ms동안 최대 한 번만 발생합니다.

주로 무한 스크롤링 페이지에서 활용합니다. 사용자가 footer에 도달하기 전에 더 많은 콘텐츠를 가져와 페이지에 추가해야 하는데, 스로틀을 통해 사용자 위치가 footer로부터 얼마나 떨어져 있는지 확인할 수 있기 때문입니다.

디바운스와 스로틀의 차이점

디바운싱과 스로틀의 가장 큰 차이점은 스로틀은 적어도 X 밀리 초마다 정기적으로 기능 실행을 보장한다는 것입니다.
Debounce 는 아무리 많은 이벤트가 발생해도 모두 무시하고 특정 시간사이에 어떤 이벤트도 발생하지 않았을 때 딱 한번만 마지막 이벤트를 발생시키는 기법입니다.
따라서 5ms 가 지나기전에 계속 이벤트가 발생할 경우 콜백에 반응하는 이벤트는 발생하지 않고 계속 무시됩니다.

참고 자료2 - web club의 예제에서 스크롤 이벤트를 통해 디바운스와 스로틀의 차이를 알 수 있습니다.

  • 마우스 휠을 크게 움직여 스크롤할 때
    -디바운스 : 마우스 휠의 움직임이 완전히 끝나고 (=스크롤을 멈출 때) count됨
    -스로틀 : 마우스 휠이 움직이는 동안 주기적으로 count됨

  • 드래그앤 드랍으로 스크롤할 때
    -디바운스 : 드랍 후에 (=스크롤을 멈출 때) count됨
    -스로틀 : 드래그 하는 동안 주기적으로 count됨

위치 구하기

1. 스크롤에 따라 달라지는 이미지 영역의 절반 지점 구하기

const slideInAt =
      window.scrollY + window.innerHeight - slideImage.height / 2;


이때 주의해야 할 것은, window.scrollY는 document의 시작점부터 카운트하는데 브라우저 화면에 보여지는 뷰포트 부분이 아니더라도 카운트 된다는 것입니다. 뷰포트보다 document가 크면 스크롤이 생깁니다.

2. 이미지의 최하단 지점 구하기

const imageBottom = slideImage.offsetTop + slideImage.height;

코드

const sliderImages = document.querySelectorAll(".slide-in");

function checkSlide(e) {
  sliderImages.forEach((slideImage) => {
    const slideInAt =
      window.scrollY + window.innerHeight - slideImage.height / 2;

    const imageBottom = slideImage.offsetTop + slideImage.height;
    
    const isHalfShown = slideInAt > slideImage.offsetTop;
    
    const isNotScrolledPast = window.scrollY < imageBottom;
    
    if (isHalfShown && isNotScrolledPast) {
      slideImage.classList.add("active");
    } else {
      slideImage.classList.remove("active");
    }
  });
}
window.addEventListener("scroll", debounce(checkSlide));

Offset

offset은 document를 기준으로 HTML element의 위치를 나타냅니다.

HTMLelement.offsetHeight : 요소의 높이
HTMLelement.offsetwidth : 요소의 폭
HTMLelement.offsetLeft : document 좌측에서 요소의 좌측까지의 길이
HTMLelement.offsetTop : document 상단에서 요소의 상단까지의 높이
HTMLelement.offsetParent : 현재 요소의 위치에 영향을 미치는 부모 요소

Window property

더 많은 속성은 MDN에서

window.scrollY : document가 수직으로 얼마나 스크롤됐는지 픽셀 단위로 반환
window.innerHeight : 스크롤을 포함한 브라우저 화면(viewport)의 높이를 말하는데, 브라우저 창틀을 제외한 내부의 높이이다.

profile
https://emewjin.github.io

0개의 댓글