저번 글에 이어서 휠 이벤트(= 스크롤) 시 화면이 fadeInOut 이 되면서 페이지가 전환되게 구현해보았다.
구현 포인트
handleScrollVertical 함수
const handleScrollVertical = useCallback( (event) => { event.preventDefault(); const scrollAmount = event.deltaY > 0 ? 1 : -1; setVisibleIndex((prevIndex) => { const newIndex = Math.max(0, Math.min(prevIndex + scrollAmount, 2)); // 3개의 항목(인덱스 0~2) return newIndex; }); }, [setVisibleIndex] );
스크롤 실행
{ passive: false } 옵션은 이벤트 리스너에 전달되는 설정 객체의 일부로, 브라우저가 해당 이벤트 리스너에서 event.preventDefault() 호출할 수 있어 스크롤 이벤트에서 중요하다.
여기 코드에서 passive: false를 사용하는 이유 handleScrollVertical 함수에서 event.preventDefault()를 호출하기 때문이다. handleScrollVertical 함수의 event.preventDefault()를 통해 기본 스크롤 동작을 막고, 대신 커스텀 스크롤 동작을 구현하려는 것이다. passive: false가 없으면 event.preventDefault()가 호출되더라도 기본 스크롤 동작을 막지 못할 수 있다.
useEffect(() => { const horizontalDiv = horizontalDivRef.current; if (horizontalDiv) { horizontalDiv.addEventListener('wheel', handleScrollVertical, { passive: false }); } return () => { if (horizontalDiv) { horizontalDiv.removeEventListener('wheel', handleScrollVertical); } }; }, []);
FadeInOut 효과
<section ref={horizontalDivRef} className="fade_container"> {[1, 2, 3].map((item, index) => ( <div key={index} className={`fade_wrap ${visibleIndex === index ? 'visible' : 'invisible'}`} style={{ position: 'absolute', top: 0, left: 0, width: '100vw', height: '100vh', transition: 'opacity 0.5s', opacity: visibleIndex === index ? 1 : 0, backgroundColor: index === 0 ? 'pink' : index === 1 ? 'purple' : 'green', }} > {item} </div> ))} </section>
.fade_container { @apply overflow-hidden whitespace-nowrap relative w-screen h-screen; } .visible { opacity: 1; } .invisible { opacity: 0; }
전체 코드
import { useCallback, useRef, useState, useEffect } from 'react' export default function Test() { const horizontalDivRef = useRef(null) const [visibleIndex, setVisibleIndex] = useState(0) const handleScrollFade = useCallback( (event) => { event.preventDefault() const scrollAmount = event.deltaY > 0 ? 1 : -1 setVisibleIndex((prevIndex) => { const newIndex = Math.max(0, Math.min(prevIndex + scrollAmount, 2)) // 3개의 항목(인덱스 0~5) return newIndex }) }, [setVisibleIndex], ) useEffect(() => { const horizontalDiv = horizontalDivRef.current if (horizontalDiv) { horizontalDiv.addEventListener('wheel', handleScrollFade, { passive: false, }) } return () => { if (horizontalDiv) { horizontalDiv.removeEventListener('wheel', handleScrollFade) } } }, []) return ( <> <section ref={horizontalDivRef} className="fade_container"> {[1, 2, 3].map((item, index) => ( <div key={index} className={`fade_wrap ${visibleIndex === index ? 'visible' : 'invisible'}`} style={{ position: 'absolute', top: 0, left: 0, width: '100vw', height: '100vh', transition: 'opacity 0.5s', opacity: visibleIndex === index ? 1 : 0, backgroundColor: index === 0 ? 'pink' : index === 1 ? 'purple' : 'green', }} > {item} </div> ))} </section> </> ) }
결과