티스토리 뷰


발생일: 2013.06.20

문제:
팀에서 제이쿼리 모바일을 쓰기로 결정하고, 처음 시작해보면서 메모해뒀던 내용이다.
노트를 정리하다가 있어 옮겨둔다.

해결책:


먼저, 간단한 소개를 보고,

초간단 샘플을 만들어볼 수 있다.


다음으로 jQuery 문서를 보면서 시작할 수 있다.


페이지

페이지를 구성하려면, `data-role="page"` 속성을 준다.
페이지에는 전체 사이트에서 유일한 id를 부여한다.

한 페이지에 여러 page를 추가할 수 있으며,
페이지가 로드되면 첫 번째 page를 찾아서 보여준다.

페이지간에는 `#pageId`로 링크를 이동하면 된다.
페이지의 제목을 설정하려면 `data-title="제목"` 속성을 할당하면 된다.

별도로 분리된 페이지의 경우 '/page2.html'과 같이 이동하면 된다.
XHR을 사용할 수 있는 경우라면, 해당 페이지의 내용을 Ajax로 불러와서 필요한 부분만 취해 추가한다.
단, 별도로 분리된 페이지를 가져올 때엔 페이지 내에 단 한 개의 `data-role="page"` 속성이 있어야 한다.

멀티 페이지를 포함한 경로는 Ajax로 가져올 수 없으며, 링크로 이동해야 한다.
이 때엔 링크에 rel="external" 속성이나 data-ajax="false" 속성을 추가하면 된다.
두 속성의 효과는 동일하지만 의미는 다르다.
  rel="external"은 다른 도메인이나 사이트로 이동하겠다는 걸 의미하지만,
  data-ajax="false"는 단순히 ajax로 가져오는 걸 하지 않겠다는 의미다.


추가:
  실제론 id 말고 `data-url` 속성을 주는 걸로도 링크를 적용할 수 있다.



뒤로 가기 버튼

뒤로 가기 버튼은 `data-rel="back"`을 링크나 버튼에 추가하는 걸로 구현할 수 있다.
이건 시스템의 뒤로 가기 버튼과 동일하며, 팝업을 닫는 등의 액션에 유용하다.
백버튼 이긴 하지만, 사용자는 여러 경로로 이 페이지를 접할 수 있으므로,
반드시 유효한 링크 주소를 추가해두는 것이 좋다.

만약, 히스토리는 변경하지 않고 그냥 이전의 트랜지션만 변경하고 싶다면,
`data-direction="reverse"` 속성을 추가하면 된다.

그렇다고 `data-rel="back"` 속성이 적용된 엘리먼트에,
`data-direction="reverse"` 속성을 추가한다고 해서, 백 버튼이 이전의 트랜잭션을 되돌리며 동작하는 건 아니다.
`data-rel="back"`은 기본적으로 보였던 것의 반대 방향으로 진행하지만,
특별히 강제하고 싶은 경우에 `data-direction="reverse"`를 명시할 수도 있다.


링크

페이지 엘리먼트에 `data-url="foo/bar"`와 같이 URL 속성을 설정하면,
해당 페이지가 로드됐을 때 브라우저의 URL값을 `data-url` 에 정의한 값으로 변경한다.
히스토리도 이 URL로 설정된다.
폼에 서브밋하거나 페이지가 리다이렉트 된 경우 등에 사용할 수 있다.


다이얼로그

다이얼로그를 띄우려면, `data-role=dialog` 속성을 주면 된다.
별도의 파일로 분리되어 있을 수도 있으며, dialog 를 띄우는 건 히스토리에 추가되지 않는다.



트랜지션



버튼이나 링크에 `data-transition="fade"`와 같은 속성을 주면 트랜지션이 적용된다.
트랜지션은 CSS3를 이용한다. (GPU 가속이 적용된다)

기본 트랜지션 값은 `fade`이다.
기본값을 변경하고 싶다면 전역 옵션을 수정하면 된다.

3D Transition을 지원하지 않는 기기(예: Android 2.x)에서는 폴백으로 `fade` 트랜지션을 선택하게 한다.
이 값을 변경하고 싶다면,

    $.mobile.transitionFallbacks.slideout = 'fade';

와 같이 설정할 수 있다.
3D 트랜지션을 지원하더라도 Android 3.x 의 경우처럼 제 성능을 내지 못하는 기기들이 있다.
배포하기 전엔 반드시 성능 테스트를 해야한다.



스크롤

스크롤이 화면 높이보다 3배 이상 큰 경우,
스크롤을 많이 한 상태에서 아이템을 클릭하면 간혹 브라우저가 죽는 버그가 있다.
전체 문서의 높이가 중요한 게 아니고, 스크롤 된 위치가 중요하다.
JQM에서는 트랜지션의 최대 스크롤 위치를 제한하는 기능이 있다.


페이지 로딩

아래처럼 호출할 수 있다.

    $.mobile.loading('show', { 옵션 }); 


미리 로드하기(Prefetching pages)

싱글 페이지 템플릿으로 분리해둔 페이지를 미리 불러올 수도 있다.

링크나 버튼에 data-prefetch 속성을 추가해두면,
`pagecreate` 이벤트가 발생했을 때 해당 페이지를 미리 불러온다.

아니면,

    // 로딩 메시지 없이 불러온다.
    $.mobile.loadPage( pageUrl, { showLoadMsg: false } );

로 해당 페이지를 미리 불러올 수도 있다.


DOM size management

jquery는 기본적으로 페이지를 이동하면 이전의 DOM을 삭제한다.
정확하게는 `pagehide` 이벤트가 발생했을 때이다.
만약 삭제했던 페이지를 다시 방문하면, 캐시된 페이지로 다시 DOM을 생성한다.
캐시되어 있지 않으면 새로 다운로드 받는다.

DOM을 통째로 삭제하는 것이기 때문에, 비동기로 로드했던 내용은 모두 삭제된다.

또한, 멀티 페이지 템플릿에는 적용되지 않으며, Ajax 로 불러온 것에만 해당된다.


Caching pages in the DOM

원한다면 만들었던 DOM을 삭제하지 않고 보관할 수도 있다.

    $.mobile.page.prototype.options.domCache = true;


아니면, 특정 페이지의 엘리먼트만 보관할 수도 있다.

    <div data-role="page" id="cacheMe" data-dom-cache="true">

스크립트로도 호출할 수 있다.

    pageContainerElement.page( { domCache: true } );



현재 페이지

현재 페이지는 `ui-page-active` 클래스를 갖는다.


다이나믹 페이지 생성

$.mobile.chagePage() 가 호출되면 아래와 같은 이벤트가 호출된다.

    1. pagebeforechange
        페이지 로딩 전

    2. pagechange
        페이지 로딩과 트랜지션이 끝난 다음

    3. pagechangefailed
        페이지 로딩에 실패한 경우


메모리에서 데이터를 가져와 페이지를 만들려면, `pagebeforechange`를 활용하는 게 좋다.
이 이벤트에서 해시를 미리 확인하고 어떤 페이지로 가는 지 바로 알 수 있기 때문이다.


페이지 스크립트


페이지마다 다시 불러와야 하는 스크립트는 page 엘리먼트 내에 추가한다.
그럼 페이지가 불려올 때마다 해당 스크립트를 실행하게 된다.

실제로는 `pageinit`에서 페이지 이름을 분기해서 호출하는 방법을 추천한다.
`pageinit`은 DOM ready와 동일하다고 생각하면 된다.

이벤트는 document에 할당하도록 한다.

만약, 페이지가 초기화 되기 전에 뭔가 컨트롤하고자 한다면,
`pagebeforecreate` 이벤트를 할당하면 된다.

(기존에 `pagecreate`를 쓰고 있었다면, `pageinit`으로 바꿔라!)


Ajax로 마크업을 불러와서 추가한 다음에, `create` 이벤트를 발생하려면 아래와 같이 하면 된다.

  $( 새 마크업 ).appendTo('.ui-page').trigger('create');


create 이벤트와 refresh 이벤트의 차이

create : 전혀 없는 것을 새로 추가했을 때
refresh: 이미 있는 것을 업데이트할 때


마우스와 터치이벤트

모바일 플랫폼마다 다르지만, 대부분 click 이벤트는 모두 제공한다.
하지만 클릭 이벤트는 500~700ms의 딜레이가 있다.
이 딜레이는 더블탭을 하거나 스크롤이나 탭을 홀드하는 걸 기다리는 것 때문에 필요한 시간이긴 하다.

이 딜레이를 없애고 싶으면 터치 이벤트를 사용하면 된다.
하지만, 터치를 지원하지 않는 디바이스(WP7, 블랙베리)도 있다.
클릭과 터치에 모두 이벤트를 바인드하면 좋겠지만, 플랫폼에 따라 두 이벤트를 모두 발생하는 경우도 있다.

이를 해결하려면 가상 이벤트를 사용하면 된다.


폰갭 같은 인앱 브라우저로 작업하기

인앱에서는 각 페이지가 로컬에 있기 때문에, Ajax를 사용할 수도 없거니와,
서버에 있는 데이터를 가져오려면 동일 근원 정책을 위배하게 된다.

이 문제는,
$.support.cors $.mobile.allowCrossDomainPages 로 해결할 수 있다.


Cross-Origin Resource Sharing 옵션을 켜려면,
$.supper.cors 값을 true로 설정하면 된다.
(블랙베리 같은 데서는 실제로 true로 설정해도, jquery core에서 제대로 설정하지 않는 버그가 있다고 한다)

도메인이 다른 페이지로 이동하게 하려면,
$.mobile.allowCrossDomainPages = true
로 설정해야 한다.
XSS 공격을 막기 위해 일부러 false로 설정해 둔 것이긴 하다.


인앱에서 주의할 것

- pushState feature를 꺼둬라.
  웹뷰에서는 URL이 보이지 않아서 이상 동작을 일으킬 수 있고, 또 굳이 이를 유지할 필요가 없기 때문이다.

- 안드로이드 웹뷰에서는 로딩 시간에 제한을 두고 있다.
  로딩 시간이 안드로이드에서 허용하는 시간보다 길면 오류가 발생할 수 있다.
  안드로이드의 loadUrlTimeoutValue를 여유있게 설정하면 된다.

- 파일명에 언더스코어를 피해라.
  폰갭이 안드로이드에 파일을 제대로 올리지 못하는 이슈가 있기 때문이다.

- 트랜지션이 깜빡일 땐 animation-fill-mode 를 써라.
  그치만, 넥서스 7 같은 데서 이 속성을 쓰면 엄청 느려지는 버그가 발견됐으니 주의해라.
  타겟을 잡고 확인한 후에 적용하는 방식으로 접근해라.



반응형
댓글
공지사항