[Web] 스크롤 시 한 번에 영역 이동하기

sean·2022년 8월 1일
1

Web

목록 보기
2/22

🛼스크롤 시 한 번에 영역 이동

요즘 사이트를 돌아다니다보면 스크롤 한 번에 div가 통째로 슝~ 올라오는 기능을 구현한 사이트들을 심심찮게 볼 수 있었다.
그래서 나도 이런 효과를 구현해보고 싶었고, 앞으로도 자주 쓸 일이 있을 것 같아서 기록해두기로 합니다!
제가 말하는 효과는 아래 페이지가 소개하는 효과입니다!

https://alvarotrigo.com/fullPage/

⚙️구현하기

1. wheel 의 기본 이벤트 제거하기

window.addEventListener('wheel', function(e) {
  	e.preventDefault();
	}, {passive: false}
)

💡 e.preventDefault()

  • 브라우저에서 특정 이벤트 발동 시 기본적으로 수행되는 동작을 취소하는 함수
  • EventListener의 옵션이 passive: false인 경우에만 사용 가능하다.

💡 wheel 이벤트에서 e.preventDefault() 적용하기

  • 위의 코드에서 {passive: false}를 제외하고 작성하면 e.preventDefault()를 적었음에도 불구하고 스크롤이 너무 잘 된다.
  • 이유) 이벤트타입 touchstart, touchmove, wheel, mousewheel에 대해서는 passive의 기본 값이 true이기 때문이다. 따라서, 명시적으로 {passive: false}를 적어주어야 한다.

2. wheeldeltaY 에 따라서 영역 이동시키기

WheelEvent에는 deltaY라는 속성이 있는데, 우리는 다음 조건만 분기시키면 된다.

  • 스크롤을 내렸을 때, 다른 영역이 올라온다 → if(event.deltaY > 0) { ... }
  • 스크롤을 올렸을 때, 올라왔던 영역이 내려간다 → if(event.deltaY < 0) { ... }

필자는 tailwindcss를 사용하고 있으므로 다음과 같이 useEffect를 사용하였다.
(position: absolute인 div의 top 속성을 조절해주었다)

    useEffect(() => {
        window.addEventListener(
            'wheel',
            function (e) {
                e.preventDefault();

                const paletteWrapper = document.querySelector('#palette-wrapper') as HTMLElement;

                //스크롤을 아래로 내리면 팔레트가 올라오고, 위로 올리면 팔레트가 내려간다.
                if (e.deltaY > 0) {
                    paletteWrapper?.classList.replace('md:top-[calc(100vh)]', 'md:top-[calc(5vw+2.5rem)]');
                } else {
                    paletteWrapper?.classList.replace('md:top-[calc(5vw+2.5rem)]', 'md:top-[calc(100vh)]');
                }
            },
            { passive: false },
        );
    });

3. 결과

해당 sectiontransition까지 넣어주어 애니메이션이 아주 부드럽게 잘 구현되었다.

🧐onScroll도 있는데 왜 굳이 onWheelpreventDefault()를 걸까요?

상단 코드에서 wheel이 아니라 scroll로 바꾸면 정상적으로 스크롤이 됩니다! (충격) 그래서 onScrollonWheel의 차이점을 계속 찾아보았어요. 그러다가 답을 얻었습니다!

이해를 위해서 원문 그대로 옮기겠습니다. (참고링크)

We can’t prevent scrolling by using event.preventDefault() in onscroll listener, because it triggers "after" the scroll has already happened.

But we can prevent scrolling by event.preventDefault() on an event that causes the scroll, for instance keydown event for pageUp and pageDown.

If we add an event handler to these events and event.preventDefault() in it, then the scroll won’t start.

🛠️추후 수정사항

위 코드에서는 window에다가 EventListener를 달았는데, 그래서 문제가 생겼습니다.
이 스크롤을 막는 효과를 적용할 페이지에 들어갔다가 다시 다른 페이지나 홈페이지로 이동했을 때에도 스크롤이 먹통이 되어버리는 현상이 발생했습니다. (너무 당연하죠ㅜ)
그래서 스크롤을 막은 페이지에서 window에 EventListener를 부착하지 않고, 해당 페이지의 모든 컴포넌트들을 감싸는 최상위 부모 컴포넌트를 만들어서 거기에 wheel을 막는 EventListener를 부착하였고, 따라서 다른 페이지들에서는 당연히 정상적인 스크롤이 가능해졌습니다!

profile
여러 프로젝트보다 하나라도 제대로, 깔끔하게.

0개의 댓글