네이버 | 진행중인 프로젝트 |
---|---|
![]() | ![]() |
모바일 브라우저는 사용자의 스크롤 조작을 감지해서 주소창/하단메뉴 UI를 on/off 하는 기능을 지원합니다.
위 GIF를 확인하면 네이버에서는 스크롤할때 UI의 on/off가 잘 이루어지는데
우측의 사이트는 예상한대로 나오지 않는 것을 확인할 수 있는데요.
이유는 붉은색의 중앙 영역에서 overflow:scroll
이 설정되어 해당 영역에서의 스크롤이 이루어질때는 UI의 on/off가 발생하지 않고
파란 영역의 상단바와 하단바에서 스크롤할 때만 on/off가 발생하는 것입니다.
다시 말해 루트영역에서 스크롤이 발생할 때만 UI의 on/off가 이루어집니다.
※ 사용자가 직접 스크롤하는 이벤트가 발생해야만 on/off가 됩니다. 코드 상에서 루트 영역의 scrollTop
을 조작함으로써 on/off를 할 수는 없습니다.
가장 간단한 해결 방법으로는 해당 영역의 height
를 설정하지 않고 overflow:scroll
을 해제하여 루트 영역에서 스크롤이 되게 설정하는 것입니다.
1번 방법으로는 제가 만들던 프로젝트에서 적용할 수 없었습니다.
메뉴를 선택해서 전체 영역에서 스크롤되게 하고 해당 메뉴 안에서 스크롤이 이뤄져야 하기 때문에 구현 방식에서 맞지 않았습니다.
이 같은 상황으로 해당 영역의 height
설정이 꼭 필요하고 영역 안에서 스크롤이 되야 하는 경우에는 다음과 같은 방법을 사용할 수 있습니다.
overflow: hidden
으로 설정하여 스크롤 이벤트를 차단루트 영역에서 필요한 코드를 자세히 알아보도록 하겠습니다.
useEffect()
에서 touchstart
, touchmove
, touchend
이벤트를 설정해줍니다.
touchstart
는 터치가 발생할 때 실행되는 이벤트입니다.
startY
는 touchmove
에서 움직인 양을 계산하기 위한 초기값입니다.
velocity
는 관성 스크롤을 위해 사용합니다.
터치 스크롤이 끝날 때 스크롤이 바로 멈춰서면 사용감이 떨어지겠죠? 스크롤 하던 방향으로 서서히 느려지면서 추가 스크롤을 하기 위해 사용됩니다.
touchmove
는 touchstart
후에 움직임이 있을 때 실행됩니다.
scrollableRef
는 하위 컴포넌트에서 forwardRef
로 참조를 받고있습니다.
하위 컴포넌트에서 다시 useImperativeHandle
을 이용하여 선택된 메뉴에 해당하는 컴포넌트의 참조를 선택하여 넘겨줍니다.
선택된 컴포넌트에서 다시 useImperativeHandle
으로 스크롤 할 부분의 current
를 current
라는 변수에 담아 전달하고 있습니다.
forwardRef
으로 받아온 Ref를 사용할 때 Ref.current.xxx
으로 사용하기 때문에 scrollableRef.current.selectRef().current.current
라는 코드가 써졌는데 하위Ref.하위Ref.current
라고 이해 하시면 됩니다.
forwardRef
에 대한 자세한 설명은 아래 링크를 참고바랍니다.
>> [React] 자식 컴포넌트의 요소를 조작하기
touchmove
에서 event.preventDefault()
를 사용하면 주소창/하단메뉴 UI의 on/off기능을 막을 수 있습니다.
해당 영역에서 스크롤이 최상단일 경우만 UI on/off가 이루어지게 추가한 구문입니다.
마지막 조건문이 터치 무브에 따라 해당 영역의 scrollTop
을 조작하는 코드입니다.
touchend
는 터치 이벤트가 종료될 때 실행됩니다.해당 영역이 최상단일 때만 스크롤을 올릴 때 UI가 나타나며
스크롤을 내릴때 UI가 잘 사라지는 모습입니다.