2011-06-18

jQuery Mobile Tip

jQuery Mobile(이후 jQM)으로 아이패드용 클리앙 뷰어를 만든 경험을 토대로 팁을 정리했습니다. 이후, 편의상 경어를 사용합니다.

data-xxx

jQM의 위젯들은 다른 jQuery 위젯이나 플러그인들과는 달리 자바스크립트로 옵션을 지정하는 대신, HTML 의 data- 속성을 이용해서 모양새와 동작을 지정한다.

가장 중요한 것은 data-role 속성인데, HTML 태그에 page, header, content, footer 에서부터 listview, navibar, button 등의 "역할"을 지정하면, jQM이 알아서 적당한 렌더링 해준다는 거다. 이를 통해서 자바스크립트 코드는 거의 손대지도 않고 순수 HTML 만으로 깔끔한 모바일 뷰를 만들어낼 수 있게 된다.

예를 들어 버튼을 만들어야 된다고 하자. 단순한 anchor 에 data-role="button" 속성을 넣는 것만으로 버튼을 만들 수 있다. 버튼 아이콘은 data-icon 으로 바꾸고, 페이지 전환 애니메이션이 필요할 경우 data-transition= slide | slideup | slidedown | pop | flip | fade 을 사용하면 되고, 또 data-direction="reverse" 으로 애니메이션 방향을 반대로 바꿀 수 있다. 만약 페이지 전환이 아니라 다이얼로그를 띄워야 할 때 anchor.rel 속성처럼 data-rel="dialog" 속성을 지정하면 된다.

이 모든 것이 JS 코드 한줄 없이도 자동적으로 이루어지게 만든, jQM 개발팀에게 박수를 보낸다.

페이지와 캐싱

페이지는 보통 header - content - footer 로 나뉘는, jQM의 가장 핵심적인 구성 요소다. 그냥 모바일 화면의 하나의 뷰라고 생각하면 된다. HTML 파일 안에 여러 개의 페이지들이 존재할 수 있다. 보통은 각 페이지들 마다 #id 를 붙여두면 되긴 한데, AJAX 로 읽어오는 페이지들의 하위 요소(예를 들면 listview)에 #id를 붙여서 jQuery로 접근하는 것은 가급적 피해야 한다.

왜냐하면 모바일 환경의 특성상 이미 방문했던 페이지에 대해서 다시 서버에 요청을 하지 않기 위해서, jQM은 이미 한번 방문했던 페이지들은 URL 을 해쉬한 키값으로 DOM 에 저장한 후 숨겨버린다. 그러므로, 동일한 #id 를 가진 페이지가 캐싱될 경우 자바스크립트에서 검색하는 게 불가능하므로, 현재 화면에 보이는 페이지를 기준으로 CSS 클래스로 찾는 것을 권한다.

그냥 페이지 전환이 발생하면 항상 div.data-role="page" 라는 게 무조건 추가된다고 생각하면 이해가 빠를 듯하다. 참고로 로컬 캐싱된 이런 페이지들에 대해 히스토리(Back-Forward) 이동을 적용하기 위해서 yourdomain.com/#/some/where 등의 로컬 주소로 변환된다는 점에 유의할 것.(트위터에서 쓰는 방식이랑 비슷한건데, 뭔가 이걸 가리키는 용어가 있었던 듯... 가물가물..)

ul-li-thumb 문제

리스트 아이템(li) 바로 아래에 이미지 태그를 넣어두면, jQM은 자동적으로 트위터와 같은 2단 레이아웃으로 바꾼다. 내부적으로 이미지에 ul-li-icon 또는 ul-li-thumb 클래스를 붙이고 li 에다가도 ul-li-has-thumb 같은 클래스를 붙여서 크기와 너비, 마진을 설정해버린다.

한편으로는 좋은 기능이지만, 원치않는 경우라고 해도 이미지 크기가 강제로 줄어들게 된다. 해결책은 리스트 바로 아래 자식 이미지를 다른 태그로 둘러싸서 jQuery 검색에 걸리지 않게 만들면 된다.

see also: http://forum.jquery.com/topic/latest-release-list-thumbnail-issue

터치 이벤트 사용하기

데스크탑에서 개발하다가 아이패드에서 테스트해보니 유독 내가 만든 버튼만 클릭이 잘 안먹는 경우가 있어서 뭔가 했는데, 가만히 생각해보니 click 이벤트와 touch 이벤트는 별개라는 사실을 잠시 잊어서 생긴 문제였다. 항상 tap (tab 이 아니다) 이벤트를 click 과 함께 등록해야 된다 :)

fixed header & footer

data-position="fixed" 를 이용하면 헤더나 푸터를 스크롤에 관계없이 화면에 고정할 수 있다. 스크롤 할 때에는 사라져서 편한 거 같은데, 막상 아이패드에서는 이게 번쩍거리거나 프레임을 떨어뜨리는 문제가 있으므로 적당히 사용해야 할 거 같다. 나도 처음에는 긴 글이 있을 때 넣으면 좋겠거니 했는데, 워낙 깜빡임이 심해서 빼버렸다. 페이지 전환 애니메이션도 너무 과하면 곤란한 듯하다.

$.mobile.ajaxEnabled = false

기본적으로, 링크를 클릭하면 jqm은 이동하려는 페이지가 DOM에 없을 때에만, ajax()를 호출해서 페이지를 자동으로 만든다.  그런데 backbone 같은 MVC 라이브러리를 사용할 경우, 이런 흐름은 달라져야 된다. 사용자가 링크를 클릭하면 관련된 모델을 fetch 하고 컬렉션을 적당히 변경한 후, 페이지는 backbone 뷰가 자동으로 만들어주는 느낌이 가장 어울릴 것이다. 즉 ajaxEnabled 옵션을 끄고 관련된 이벤트들을 직접 바인딩해서 처리하면 된다.

소소한 팁들

  • 버튼을 헤더의 오른 편으로 정렬하기 : 버튼의 class 속성에 ui-btn-right 를 추가하면 된다.
  • data-backbtn="false": jQM 1.0a4.1 까지는 페이지 전환시 자동적으로 헤더에 Back 버튼이 추가되므로, 돌아가기 버튼이 필요없는 메인 페이지 등에서는 이 속성을 지정하면 된다.
  • 원치않는 nested list : ul-li-thumb 와 마찬가지로 li 바로 아래에 ul 이나 ol 이 있으면 자동적으로 페이지가 만들어지므로, 다른 태그로 둘러싸면 된다.
  • 사용자가 추가한 버튼에 live("click tap") 을 지정하면 이벤트가 2개 발생되는 모양이다. 그냥 tap 만 넣어도 컴퓨터에서는 잘 동작한다.
  • 자바스크립트로 리스트 아이템을 추가한 후 listview("refresh")를 해도 그 안에 있는 inset listview 는 별도의 쿼리를 통해서 listview 위젯으로 만들어야 한다. 샘플 코드는 여기 http://jsfiddle.net/Reiot/CpudD/