250x250
Notice
Recent Posts
Recent Comments
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

진스

휠 이벤트,터치 이벤트,스크롤을 원하는 속도로 부드럽게 이동하기 본문

JavaScript

휠 이벤트,터치 이벤트,스크롤을 원하는 속도로 부드럽게 이동하기

입방정 2024. 6. 14. 13:45
728x90

메인 상단에 영상 + 이미지 스와이프 배너가 있음
pc와 모바일에서  휠을 내리거나 , 밑으로 스와이프를 하면 자연스럽게 메인배너 밑으로 스크롤 이동되길 원함


기본적으로 모바일에서 touch이벤트시에
  window.scrollTo({
            top: targetScrollY,
            behavior: 'smooth'
        }); 이부분만으로는 좀더 빠른 스크롤이동이 안됨

 

 

 

그래서 작성한 코드:

///////////////////////////메인슬라이드 휠 동작
let isScrolling = false;
let isWheeling = false;
const mainVisualElement = document.querySelector('.mainVisual');
const mainVisualHeight = mainVisualElement.clientHeight;

document.addEventListener('wheel', function(event) {
    const scrollTop = window.scrollY;
    const SCROLL_THRESHOLD = 0;

    if (!isWheeling && event.deltaY > SCROLL_THRESHOLD && scrollTop < mainVisualHeight) {
        event.preventDefault();
        isWheeling = true;
        isScrolling = true;

        const targetScrollY = mainVisualHeight;
        const duration = 500; // 애니메이션 지속 시간 (ms)
        const startTime = performance.now();
        const startScrollY = window.scrollY;

        function scroll() {
            const elapsed = performance.now() - startTime;
            const progress = Math.min(elapsed / duration, 1); // 진행률 계산 (0~1 사이 값)
            const easeInOutQuad = t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; // 이징 함수 정의 (선택 사항)
            const easedProgress = easeInOutQuad(progress); // 선택적으로 이징 함수를 적용할 수 있습니다.
            const newScrollY = startScrollY + (targetScrollY - startScrollY) * easedProgress;
            window.scrollTo(0, newScrollY);

            if (progress < 1) {
                requestAnimationFrame(scroll);
            } else {
                isScrolling = false;
            }
        }

        requestAnimationFrame(scroll);

        setTimeout(() => {
            isWheeling = false;
        }, 500); // 휠 애니메이션이 끝날 때까지 대기
    }
}, { passive: false });

window.addEventListener('scroll', function() {
    const scrollTop = window.scrollY;

    // 메인 비주얼을 벗어나면 isScrolling 상태를 해제
    if (scrollTop >= mainVisualHeight) {
        isScrolling = false;
    }
});


///////////////////////////메인슬라이드 모바일 스와이프 동작
let touchStartY = 0;
let touchEndY = 0;
const swipeThreshold = 50; 
const duration = 500; // 애니메이션 지속 시간 (ms)

mainVisualElement.addEventListener('touchstart', function(event) {
    touchStartY = event.touches[0].clientY;
});

mainVisualElement.addEventListener('touchmove', function(event) {
    touchEndY = event.touches[0].clientY;
    // 위로 스와이프할 때 preventDefault 활성화
    if (touchStartY > touchEndY && window.pageYOffset < mainVisualHeight) {
        event.preventDefault();
    }
});

mainVisualElement.addEventListener('touchend', function(event) {
    touchEndY = event.changedTouches[0].clientY;

    if (Math.abs(touchStartY - touchEndY) > swipeThreshold) {
        if (touchStartY > touchEndY && window.pageYOffset < mainVisualHeight) {
            moveMainVisual(mainVisualHeight); // 위로 스와이프할 때
        } else if (touchStartY < touchEndY && window.pageYOffset >= mainVisualHeight) {
            moveMainVisual(0); // 아래로 스와이프할 때
        }
    }
});

function moveMainVisual(targetScrollY) {
    const startScrollY = window.scrollY;
    const startTime = performance.now();

    function scroll() {
        const elapsed = performance.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);
        const easeInOutQuad = t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
        const easedProgress = easeInOutQuad(progress);
        const newScrollY = startScrollY + (targetScrollY - startScrollY) * easedProgress;
        window.scrollTo(0, newScrollY);

        if (progress < 1) {
            requestAnimationFrame(scroll);
        }
    }
    scroll();
}

728x90
Comments