본문 바로가기

프론트엔드

safari, iPhone 예외 상황 대응하기(Navigation Gestures, new Date)

  • 프로젝트: vegimap, tracking map
  • 키워드: safari, iPhone, navigation gestures, date constructor, cross browsing
  • 상황 1
    1. vegimap은 지도가 화면 전체를 차지하고 있다.
      vegimap 메인 화면
    2. iphone에서 touch gesture로 지도를 이동하다보면 navigation gesture가 작동하여 페이지가 이전/이후로 이동해버릴 때가 있다.

    3. 지도 타일을 터치할 때는 navigation gesture가 작동하지 않도록 하고자 한다.
  • 해결방법 1
    1. 특정 DOM element를 touch했을 때, navigation gesture가 실행되지 않도록 하는 custom hook을 작성한다.
        // useBlockNavigationGesture.ts
      import { useEffect } from 'react';
      
      const useBlockNavigationGesture = (elementId: string): null => {
        function blockNavigationGesture(e: TouchEvent) {
          const { target } = e.touches[0];
          if ((target as HTMLElement).tagName !== 'IMG' || (target as HTMLImageElement).src?.includes('markers')) return;
      
          const { clientX } = e.touches[0];
          if (clientX > 50 && clientX < window.innerWidth - 50) return;
          e.preventDefault();
        }
      
        useEffect(() => {
          const mainElement = document.getElementById(elementId);
          mainElement?.addEventListener('touchstart', blockNavigationGesture);
          return () => {
            mainElement?.removeEventListener('touchstart', blockNavigationGesture);
          };
        }, [elementId]);
      
        return null;
      };
      
      export default useBlockNavigationGesture;

      먼저 naver map tile은 IMG 태그이고, Marker image에 대해서는 touch가 정상적으로 이루어져야하기 때문에, tagName이 IMG가 아니거나, 마커인 경우에는 바로 return 한다.

      그 후 touch한 부분의 clientX 값이 화면의 왼쪽(< 50)이나 오른쪽(> window.innerWidth - 50)이면, 'e.preventDefault()'를 실행하여 navigation gesture의 실행을 막는다.

      preventDefault() 메서드는 어떤 이벤트를 명시적으로 처리하지 않은 경우, 해당 이벤트에 대한 사용자 에이전트의 기본 동작을 실행하지 않도록 지정합니다.

    2. custom hook을 NAVER MAP element에 적용한다.
        // MapSection.tsx
      useBlockNavigationGesture(mapSectionId);
      
      return (
        <>
          <MapSection id={mapSectionId}>
            <NaverMap {...} />
            ...
          </MapSection>
          ...
        </>
      );


    3. naver map tile에 대해서는 navigation gesture 없이 map move gesture만 작동하고, marker click 이벤트는 기존과 똑같이 동작하는 것을 확인했다!


  • 상황 2
    1. Date를 생성하고 두 date의 시간 차이를 구하는 로직이 있다.
        const startTime = new Date('2022-04-09 06:00:00');
      const endTime = new Date('2022-04-09 23:59:59');
      
      endTime.getTime() - startTime.getTime()
    2. 크롬에서는 잘 작동하지만 safari에서는 정상적으로 작동하지 않는다.

  • 해결 방법 2
    1. safari는 특정 형식의 string consturctor를 제대로 parsing하지 못한다는 것을 알게 되었다.
      safari console

      MDN Date.parse 설명


    2. dayjs 등의 라이브러리를 써도 되지만, 간단한 로직이기 때문에 js에서 지원하는 공식적인 constructor 형식을 사용하기로 한다.
      https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date#several_ways_to_create_a_date_object
        const startTime = new Date(2022, 3, 9, 6, 0, 0); // 월은 0부터 시작
      const endTime = new Date(2022, 3, 9, 23, 59, 59); // 월은 0부터 시작


    3. 이제 사파리에서도 정상적으로 Date 객체가 생성된다!