[JS] Scroll에 대한 정리

Dev.Jo·2021년 3월 22일
6

JS

목록 보기
2/7

이 글은 js30의 13강 Slide in on Scroll을 정리한 글입니다

문제

스크롤 할 때 이미지 절반 위치에서 나타나게 해주세요!


한 문장 정리

window.addEventListener("scroll") 이벤트로부터 이미지의 절반 좌표위치viewport 밑바닥 좌표위치를 얻은 다음, 둘의 좌표위치를 비교해 처리


Step 0

window.addEventListener("scroll", checkslide);

window 인터페이스의 scroll event스크롤을 하면 콜백함수 checkslide를 발생시킵니다

주의점

scroll event는 아주 미세한 스크롤에도 반응하기 때문에 debounce를 통해 과부화 및 리소스 낭비를 방지합니다

debounce란?

debounce를 적용해 수백번, 수천번의 스크롤 이벤트 요청에도 마지막의 이벤트 요청단 한번만 이벤트 처리를 수행 할 수 있습니다

debounce 함수 코드에 대해서는 이 글에서 따로 설명하지 않습니다

debounce 적용

window.addEventListener("scroll", debounce(checkslide) );

이제부터 콜백함수 checkslide 함수를 정의하겠습니다

function checkslide(e){
	....
    ....
}

Step1

document.body.clientHeight

웹 페이지 body의 높이입니다

document.height는 권장되지 않습니다- by MDN

window.innerHeight

브라우저의 현재 높이입니다 (viewport의 높이라고도 합니다)

  • 주소 표시창은 포함하지 않습니다

Step2 Viewport의 밑바닥 절대좌표 구하기

window.scrollY

  • document가 수직으로 얼마나 스크롤됐는지 픽셀 단위로 반환합니다
  • window.pageYOffset과 똑같은 기능입니다
  • 차이점은 scrollY는 IE9에서 지원하지 않습니다

scrollY + window.innerHeightviewport의 가장 밑바닥 절대 위치를 알려줍니다


Step 3 이미지 절반위치의 절대좌표 구하기

  1. image.offsetTopdocument.body로부터 떨어진 image 위치입니다

  2. image 절반위치의 절대좌표image.offsetTop + image.height/2입니다


Step 4

만약 viewport의 맨 밑바닥 좌표 > image 절반위치의 절대좌표라면

=> 이미지 절반 이상이 viewport에 보였다는 뜻이기 때문에 이미지가 나타나야 됩니다

  1. isHalfShown라는 변수를 만들어 담아둡니다
const viewportBottom = window.innerHeight + window.scrollY;
const imageHalfBottom = sliderImage.offsetTop + sliderImage.height / 2;

const isHalfShown = viewportBottom > imageHalfBottom;
  1. 스크롤한 뒤 imageviewport에서 완전히 위로 사라졌다면(지나갔다면) 원래대로 숨겨줘야합니다

  2. 변수 isNotScrollPast를 두어 imageviewport를 지나갔는지 판단합니다

const isNotScrollPast = 
      window.scrollY < sliderImage.offsetTop + sliderImage.height;
  1. 이미지를 보여주는 active한 상태를 판단합니다

이미지 절반 이상이 노출됬고 and 아직 이미지가 viewport에 남아있다면 active 클래스를 추가합니다

if (isHalfShown && isNotScrollPast) {
  	sliderImage.classList.add("active");
} else {
     	sliderImage.classList.remove("active");
}

css

active 상태면 opacity위치를 원래대로 되돌립니다

// 이미지 클래스 <image class="align-right(left) slide-in">

//최초 이미지는 투명 opacity:0

.slide-in {
        opacity: 0;
        transition: all 0.5s;
}

// 왼쪽, 오른쪽에 따라 이미지의 x좌표를 옮겨줍니다

.align-left.slide-in {
        transform: translateX(-30%) 
        scale(0.95);
}

.align-right.slide-in {
        transform: translateX(30%) 
        scale(0.95);
}

// active 상태면 원상복구합니다

.slide-in.active {
        opacity: 1;
        transform: translateX(0%) 
        scale(1);
}

전체코드

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);
        };
      }


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

function checkSlide(e) {
        sliderImages.forEach((sliderImage) => {
          const viewportBottom = window.innerHeight + window.scrollY;
          const imageHalfBottom =
            sliderImage.offsetTop + sliderImage.height / 2;
          const isHalfShown = viewportBottom > imageHalfBottom;

          const isNotScrollPast =
          window.scrollY < sliderImage.offsetTop + sliderImage.height;
          if (isHalfShown && isNotScrollPast) {
            sliderImage.classList.add("active");
          } else {
            sliderImage.classList.remove("active");
          }
        });
      }

window.addEventListener("scroll", debounce(checkSlide));
profile
소프트웨어 엔지니어, 프론트엔드 개발자

0개의 댓글