지난번에 useRef 를 활용, 버튼을 클릭하여 특정 위치로 이동하는 이벤트를 만들어보았다.

이번 포스팅은 그와 함께 쓸 스크롤을 방향을 인식하여 위,아래로 한단계씩 이동하는

스크롤을 만들어볼 것이다.

일단 스크롤 이벤트를 정의할 때, 크게 세가지로 구분해보자.

1.scroll

2.mouse wheel

3.touch

이렇게 3가지가 있는 데, 필자의 대상은 핸드폰에서 터치로 스크롤 이동하기 때문에 3번 터치 이벤트를 세부적으로 알아보면,

1. touch start -> 터치를 시작할 때 이벤트 발생

2. touch move -> 터치 진행중일 때 이벤트 발생, 터치중일때는 다수의 이벤트가 발생한다.

3. touch end -> 터치가 끝났을 때 이벤트 발생

4. touch cancle -> 터치를 취소할 때 이벤트 발생, 가량 터치중일 때 다른 웹페이지로 이동한다거나 접속장애로 페이지가 다운될 때에도 발생될 수 있다.

통상적으로는 터치가 시작할때의 좌표값을 인지하고, 터치가 종료되었을 때의 좌표값을 인지하여

이벤트를 발생시키므로, 1 & 3번을 활용하여 이벤트를 작성해보자.

아래 포스팅을 확인하면, useRef 의 설정은 동일하다.

위 포스팅의 코드를 유지한 채 아래 코드를 추가한다.

* 필요한 부분만 넣었으므로, 상관없는 코드는 배제하고 작성하겠다.

1. JS 부분

 
 let start_y : any = null; // 시작 Y축 좌표
  let end_y : any = null; // 시작 Y축 좌표
  let index = 0; // 페이지 번호

useEffect(()=>{
    const script = document.createElement('script');
    document.getElementById('app')?.scrollTo(0, 0); // 첫 렌더시 스크롤이 최상단 고정된다

  window.addEventListener("touchstart", initTouch); // 터치 스타트 이벤트를 initTouch에 부여
  window.addEventListener("touchend", (e) => { // 터치 엔드 이벤트를 swipeEnd에 부여
    window.addEventListener("touchend", swipeEnd)
  }, { passive : true});
  }, [])

const initTouch = (e : any) => { 
    e.preventDefault();
    start_y = e.touches[0].pageY; //최초 스타트 시 Y축 좌표를 start_y 변수에 저장한다.
  };

 const swipeEnd = (e:any) => {
    e.preventDefault();
    end_y = e.changedTouches[0].pageY; // 터치가 끝났을 때 Y축 좌표를 end_y 변수에 저장한다.
    if(start_y > end_y){ // 위에서 아래로 이동
      if(index === 0){ 
        element.main.current?.scrollIntoView({ behavior: 'smooth',  block: 'start'});
      }else if(index === 1){
        element.intro.current?.scrollIntoView({ behavior: 'smooth',block: 'start' });
      }else if(index === 2){
        element.customer.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }else if(index === 3){
        element.worker.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }else if(index === 4){
        element.labor.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }else if(index === 5){
        element.schedule.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }else if(index === 6){
        element.wage.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }
      if(index <= 6){
        index += 1;
      }
    }else if(start_y < end_y){  // 아래에서 위로 이동
      if(index === 7){
        element.wage.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 6){
        element.schedule.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 5){
        element.labor.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 4){
        element.worker.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 3){
        element.customer.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 2){
        element.intro.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }else if(index === 1){
        element.main.current?.scrollIntoView({ behavior: 'auto', block: 'start' });
      }
      if(index >= 0){
        index -= 1;
      }
    }
}

2. HTML 부분

<div id='app' style={{overflowY : 'scroll' }} >
          <Section position={`relative`} ref={element.main}>. // 0페이지
            <SectionInner>
              <Main />
            </SectionInner>
          </Section>
         <Section position={`relative`} ref={element.intro}>  // 1페이지
            <SectionInner>
              <Intro />
            </SectionInner>
          </Section>
         <Section position={`relative`} ref={element.customer}>  // 2페이지
            <SectionInner>
              <CustomerStepper />
            </SectionInner>
          </Section>

          <Section position={`relative`} ref={element.worker}> // 3페이지
            <SectionInner>
              <WorkerStepper />
            </SectionInner>
          </Section>

          <Section position={`relative`} ref={element.labor}> // 4페이지
            <SectionInner>
              <LaborStepper />
            </SectionInner>
          </Section>

          <Section position={`relative`} ref={element.schedule}> // 5페이지
            <SectionInner>
              <ScheduleStepper />
            </SectionInner>
          </Section>
          <Section position={`relative`} ref={element.wage}> //6페이지
            <SectionInner>
              <WageStepper />
            </SectionInner>
          </Section>
</div>

 

브라우저 호환성 때문인지, 크롬 개발자모드에서 핸드폰모드로 할시,

터치 스크롤을 할때 scrollIntoView({ behavior: 'auto', block: 'start' });

auto모드는 잘 동작하지만,

scrollIntoView({ behavior: 'smooth', block: 'start' });

smooth 모드는 동작하지 않았다. 왜 이러지 하면서 실제 핸드폰으로 테스트해보니 잘 동작한다.

다양한 기기에서 테스트해보길 권장한다.

 

+ Recent posts