- 프로젝트: 채식 지도
- 키워드: Hammer.js, swipe event, mobile swipe gesture, touch-action
- 상황
- 뒤로가기, Sheet 내리기, Sheet 올리기 동작은 버튼을 눌러 실행할 수 있다.
(뒤로가기는 '<' 버튼, Sheet 내리기는 'X' 버튼, Sheet 올리기는 '^' 버튼)
- 모바일 기기에서 버튼을 하나하나 누르는 것은 불편하기 때문에, 뒤로가기(swipe right), Sheet 내리기(swipe bottom), Sheet 올리기(swipe top)를 swipe 이벤트를 통해 실행하고자 한다.
- 뒤로가기, Sheet 내리기, Sheet 올리기 동작은 버튼을 눌러 실행할 수 있다.
- 해결 방법
- js로 직접 구현할 수 있겠지만, 다양한 브라우저를 대응하고 threshold를 일일이 구현하는 것보다는 간단하게 Hammer.js 라이브러리를 사용하기로 한다.
yarn add hammerjs yarn add -D @types/hammerjs
- 이벤트를 추가하고자 하는 element를 Hammer 생성자에 넘기고, on API를 이용하여 이벤트를 연결한다.
// ListSection.tsx // Sheet가 펼쳐졌는지 나타내는 상태 const [isListExpanded, setIsListExpanded] = useState(false); const toggleListExpanded = () => { setIsListExpanded((expanded) => !expanded); }; ... useEffect(() => { let hammer: HammerManager; // DOM 렌더링이 끝난 후 동적 import import('hammerjs').then(() => { const listSection = document.querySelector<HTMLElement>('.list-section'); if (!listSection) return; hammer = new Hammer(listSection); // 수직, 수평 방향 모두 이용할 것이므로 DIRECTION_ALL 사용 hammer.get('swipe').set({ direction: Hammer.DIRECTION_ALL, }); // Sheet 올리기 hammer.on('swipeup', () => { setIsListExpanded(true); }); // Sheet 내리기 hammer.on('swipedown', () => { setIsListExpanded(false); }); // 뒤로가기 hammer.on('swiperight', () => { 뒤로가기함수(); }); }); return () => { hammer.destroy(); }; }, []); return ( <ListSection isListExpanded={isListExpanded} className="list-section"> ...Sheet 안의 내용... </ListSection> );
- 이제 ListSection(Sheet UI)에 대해 swipe 이벤트가 감지된다.
다만 문제인 것은 ListSection 내부에 스크롤 영역이 있는 경우이다. 스크롤 영역은 touch action이 발생할 수 있는 영역이기 때문에(swipedown하여 스크롤을 내리는 행위 등) Hammer.js의 swipe이벤트가 작동하지 않는다.
예를 들어, Sheet가 올라와 있는 현재 상황에서 스크롤 영역(매장 목록 리스트, StoreList)을 swiperight(뒤로 가기)해도 Hammer.js가 작동하지 않는다.
swipeup, swipedown은 스크롤을 우선적으로 해야하기 때문에 Hammer의 이벤트(Sheet 올리기/내리기)가 작동하지 않는 것이 맞지만, swiperight 이벤트까지 막힐 이유는 없다.
- 이 버그는 매장 목록(StoreList)의 style에 touch-action CSS를 추가하여 해결할 수 있다.
이제 StoreList에서 수직(y) 방향의 스크롤은 의도대로 동작하고, 수평(x) 방향의 swiperight는 부모 element인 ListSection의 Hammer 이벤트(뒤로 가기)가 작동한다.touch-action: pan-y;
- 의도대로 swipe 이벤트가 작동하는 것을 확인할 수 있다!
- js로 직접 구현할 수 있겠지만, 다양한 브라우저를 대응하고 threshold를 일일이 구현하는 것보다는 간단하게 Hammer.js 라이브러리를 사용하기로 한다.
'프론트엔드' 카테고리의 다른 글
safari, iPhone 예외 상황 대응하기(Navigation Gestures, new Date) (0) | 2022.04.21 |
---|---|
Web Worker로 setTimeout을 백그라운드에서 유지하기 (0) | 2022.04.20 |
모바일 기기에서 scroll 관련 버그 대응하기 (0) | 2022.04.02 |
Storybook에서 user interactions 테스트하기 (2) | 2022.03.15 |
JS library에서 cjs, esm format 모두 지원하기 (0) | 2022.03.09 |