Пишем простое приложение на jQuery Mobile

    imageФреймворк jQuery Mobile вышел уже относительно давно, но только сейчас мне удалось им заняться. До этого имел дело с jQTouch и Sencha Touch. У каждого из них есть свои плюсы и минусы, но сегодня речь пойдет именно про разработку на jQuery Mobile. Для получения базового опыта я опишу создание простого приложения с несколькими страницами, интеграцией с твиттер и гуглокартами, ну и набором базовых элементов. Поехали!

    Итак, сначала подключим фреймворк и стили.
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.css" />
    <script src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.js"></script>
    

    Теперь примемся за страницы. Тут стоить отметить схожесть jQuery Mobile и jQTouch — все приложение это одна html страницы, на которой отмеченные особым образом div`ы являются «страницами» приложения. Базовый вид такой «страницы приложения» имеет вид:
    <div data-role="page"> 
    	<div data-role="header">...</div> 
    	<div data-role="content">...</div> 
    	<div data-role="footer">...</div> 
    </div> 
    

    Параметр data-role задает роль div`а: страница, header, содержимое страницы или footer. Так же обязательно надо задавать параметр id для div data-role=«page», чтобы можно было навигироваться по приложения.

    Сразу стоит упомянуть еще об одном параметре data-theme. Данный параметр применим ко всем элементам страницы и определяет, какой из доступных по умолчанию стилей использовать. Примеры доступных тем можно посмотреть вот тут.

    Итак, на главной странице нашего приложения будет меню, элементы которого будут вести на страницы с примерами. Чтобы сделать меню нам понадобится список ul. Выглядеть это будет вот так:
    <ul data-role="listview" data-inset="true" data-theme="a">
    	<li><a href="#twitter_page">Twitter example</a></li>
    	<li><a href="#map_page">Map example</a></li>
    	<li><a href="#search">Search example</a></li>
    	<li><a href="#about">About</a></li>
    </ul> 
    

    О параметрах тега ul:
    • data-role=«listview» — показывает что это список, к которому нужно применить стилизацию;
    • data-inset=«true» — отображение списка не на всю ширину экрана, если нет, то эквивалентно false;
    • data-theme=«a»- применение цветовой схемы а.

    В jQuery Mobile можно найти массу типов списков: простые, с иконками, с изображениями и прочие и прочие. Примеры можно посмотреть вот тут.

    А еще мне хочется, чтобы в тулбаре была кнопка с настройками. Сделать это очень просто:
    <a href="#settings" data-icon="gear" class="ui-btn-right">Options</a>
    

    Как видно, данная кнопка ведет на страницу с настройками, имеет иконку шестеренки (data-icon=«gear») и расположена в правой части тулбара(class=«ui-btn-right»). Во фреймворке уже есть набор предопределенных иконок, посмотреть их можно тут.

    В конечном итоге главная страница будет выглядеть вот так:
    <div data-role="page" id="main_page" data-theme="b">
    	<div data-role="header" >
    		<h1 id="twi_acc">Home page</h1>
    		<a href="#settings" data-icon="gear" class="ui-btn-right">Options</a>
    	</div>
    	<div data-role="content" >	
    		<ul data-role="listview" data-inset="true" data-theme="a">
    			<li><a href="#twitter_page">Twitter example</a></li>
    			<li><a href="#map_page">Map example</a></li>
    			<li><a href="#search">Search example</a></li>
    			<li><a href="#about">About</a></li>
    		</ul>
    	</div>
    	<div data-role="footer">
    	</div>
    </div>	
    

    Теперь перейдем к созданию остальных страниц. Займемся страницей настроек. На ней мы расположим некоторые из элементов формы, полный список которых можно посмотреть тут.

    Руководство рекомендует группировать все элементы внутри определенного дива:
    <div data-role="fieldcontain">					
    </div>	
    

    Последуем данной рекомендации.

    Расположим на форме следующие элементы.
    Поле ввода
    <label for="name">My name:</label>
    <input type="text" name="name" id="name" value=""  />
    

    Большое текстовое поле
    <label for="textarea">About myself:</label>
    <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
    

    Слайдер, задав его максимально, минимальное и текущее значения
    <label for="slider">Value this site:</label>
    <input type="range" name="slider" id="slider" value="0" min="-50" max="50" />
    

    Переключатель
    <label for="slider2">Value this site:</label>
    <select name="slider2" id="slider2" data-role="slider">
    	<option value="off">Like</option>
    	<option value="on">Dislike</option>
    </select> 
    

    И селектор
    <select name="select-choice-1" id="select-choice-1">
    	<option value="standard">Tired</option>
    	<option value="standard">Happy</option>
    	<option value="standard">Sick</option>
    	<option value="standard">Sunny</option>
    </select>
    

    На этом со страницей настроек все. Кстати, если запустить имеющий код и перейти на только что созданную страницу, то можно увидеть, что автоматом была создана кнопка «Back». Мелочь, а приятно.

    Теперь создадим еще простую страницу — страницу поиска. На ней у нас будут два главных элемента — поле ввода и список результатов.
    <div data-role="content" >	
    	<label for="search">Search</label>
    	<input type="search" name="password" id="search" value="" />
    	<ul data-role="listview" data-inset="true" id="searchresult">					
    	</ul>
    </div>
    

    Теперь обратимся к яваскрипту. Забиндим для поле ввода на событие keyup наполнение списка результатов.
    $("#search").keyup(function(){
    	var res = shuffle(monthes);
    	var list='';
    	$.each(res, function(index, value) {
    		list+='<li role="option" tabindex="0" data-theme="a" class="ui-btn ui-li ui-btn-up-a"><div class="ui-btn-inner"><div class="ui-btn-text">'+value+'</div><span class="ui-icon ui-icon-arrow-r"></span></div></li>';
    	});							
            $("#searchresult").html(list);	
    });
    

    Несколько слов о коде. В первой строке мы перемешиваем имеющийся массив. Функция shuffle ниже.
    var shuffle = function(o){ //v1.0
    	for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    		return o;
            };
    

    Затем мы создаем сам список. Создавать приходится таким образом, потому что происходит динамическое добавление элементов списка и фреймворк уже не будет их обрабатывать, для навешивания нужных стилей и параметров. Но возможно есть способ и лучше.

    Теперь создадим пару интересных страниц. Первая будет работать с твиттером по средством @Anywhere. Сначала подключим нужные библиотеки:
    <script src="http://platform.twitter.com/anywhere.js?id=key_value&v=1" type="text/javascript"></script>
    

    Для получения ключа нужно зарегистрироваться вот тут.
    Затем создаем код нужной нам странички.
    <div data-role="page" id="twitter_page" data-theme="b">
    	<div data-role="header" >
    		<h1>Simple twitter example</h1>
    	</div>
    	<div data-role="content" >	
    		<div id="twi_list"></div>
    	</div>
    	<div data-role="footer">				
    	</div>
    </div>
    

    А теперь самое главное — яваскрипт код, который будет выполняться, когда будет открываться нужная нам страница. Для отслеживания этого события существует специальный event — pageshow. Об остальных событиях читаем тут.
    $('#twitter_page').live('pageshow',function(event, ui){					
    	twttr.anywhere(function(T) {			
    		T.User.find('andrebrov').timeline().first(20).each(function(status) {					
    			$('div#twi_list').append('<p>' + status.user.name + ': ' + status.text + '</p>');
    		});	
    						
    	});					
    });
    

    Подробности работы с @Anywhere можно прочитать по ссылке.
    Открыв созданную нами страницу мы видим, что некоторое время она остается пустой — грузятся твиты. Чтобы дать пользователю понять, что в данных момент что-то происходит добавим спиннер. Тогда код будет выглядеть вот так:
    $('#twitter_page').live('pageshow',function(event, ui){					
    	twttr.anywhere(function(T) {			
    		$.mobile.pageLoading();	
    		var j=0;
    		T.User.find('andrebrov').timeline().first(20).each(function(status) {					
    			$('div#twi_list').append('<p>' + status.user.name + ': ' + status.text + '</p>');
    			j++;
    			if (j==1){
    				$.mobile.pageLoading(true);
    			}
    		});							
    	});					
    });
    

    Про спиннер и прочие утилиты читаем тут.

    Теперь займемся страницей карты. Вначале опять же подключим нужные скрипты
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    

    Затем создадим страницу
    <div data-role="page" id="map_page" data-theme="b">
    	<div data-role="header" >
    		<h1>Map example</h1>
    	</div>
    	<div data-role="content" >	
    		<div id="map_canvas"></div>
    	</div>
    	<div data-role="footer">						
    	</div>
    </div>
    

    Элемент map_canvas и будет содержать карту. Зададим ему стиль
    #map_canvas{
    	width:100%;
    	height: 100%; 	
    	position:relative;
    	top:0px;
    }
    

    И добавим javascript-код, который будет определять текущее местоположение, относительно него центрировать карту и добавлять в центр маркер. На этот маркер мы кроме прочего повесим событие на его нажатие.
    $('#map_page').live('pageshow',function(event, ui){					
    	navigator.geolocation.getCurrentPosition(function(location) {						
    		var point = new google.maps.LatLng(location.coords.latitude, location.coords.longitude);
    		var myOptions = {
    			zoom: 13,
    			center: point,
    			mapTypeId: google.maps.MapTypeId.ROADMAP
    		};
    		var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
    		var marker = new google.maps.Marker({position: point,map: map});						
    		google.maps.event.addListener(marker, 'click', function() {
    			alert("Current coodinates are: latitude "+location.coords.latitude+", longitude "+location.coords.longitude);
    		});
    	});	
    });
    

    И, наконец, страница обо мне =) На ней интересными элементами будут элементы списка:
    Разделитель с закруглениями
    <li data-role="list-divider" role="heading" tabindex="0" class="ui-li ui-li-divider ui-bar-b ui-corner-top"></li>
    

    Ссылка, открывающая почтовый клиент
    <li><a href="mailto:mailme@gmail.com" class="ui-link-inherit">EMail me</a></li>
    

    Ссылка, приводящая к набору номера
    <li><a href="tel:+79000000000" class="ui-link-inherit">Call me</a></li>
    

    О типах ссылок читаем здесь.

    Итак, наше приложение готово!

    Итоговый результат.
    Исходники.
    Документация

    Приятной всем работы!
    Поделиться публикацией
    Комментарии 42
      +3
      ссылка на результат, для удобства.
      Вообще потрясающий тьюториал!
      Побольше бы таких на хабре.
      Потестировал на Desire (HD Dolphin Brawser) — возникли некоторые сложности.
      Карта не открылась — хотя местоположение запросил.
      В поиске какие-то глюки.
      Возможно это проблемы браузера.
        0
        кстати, расскажите мне как пользоваться сием штрихкодом, есть какой-то софт который переходит по ссылке по штрихкоду???
        или это только для андроидов?
        на Win 6.5 есть такое?
          0
          www.appbrain.com/app/barcode-scanner/com.google.zxing.client.android для андроида самая популярная BarCode Scanner
          Пользоваться просто — включаешь прогу — появляется вид через камеру и полосочка — наводишь, например, на экран. Програ распознает и предлагает открыть. В зависимости от вида ссылки откроется или маркет или браузер или там почта к примеру.
            0
            прикольно, а под винмобайл что-нибудь есть?
              0

              к примеру — кликабельно.
              Не пользовался.
      0
      Я как понимаю это можно потом упаковать в phonegap или appcelerator titanium?
        0
        Ну вообще да.
        +2
        Жаль, что на кнопках проявляются артефакты и искажают графику.
          +1
          iPhone 4, карта так и не загрузилась. В разделе Twitter, была продолжительная пауза перед «Loading», немного подождал и загрузилось.
            0
            Android 2.2 ни карты ни твиттера ни поиска, вообще ничего, только навигация по страницам работает.
              0
              Android 2.2, загрузился твиттер, но не сразу, а секунд через 15…
                0
                А да, теперь заработал твиттер и поиск заработал. Карты до сих пор не пашут.
            0
            Протестировал на Opera Mobile 10 и на родном internet explorer (HTC Diamond II c WM6.5).
            В опере условно (упрощенно) отобразилась тема, но карта и твиттер не работали, а в ie не подцепилась даже тема.
              0
              прочитал внимательно, поддерживается только windows phone
              0
              На правах оффтопа и здравого любопытства:
              Есть ли подобные… «фреймворки» на других js-фреймворках? Какие сейчас модно использовать, кроме jQuery Mobile?
              Хочется сравнить и думать что использовать для конкретного проекта.
                +1
                Sencha Touch 1.0 на основе ExtJS (или от создателей EXtJS)
                Sencha Touch, the first HTML5 mobile JavaScript framework that allows you to develop mobile web apps that look and feel native on iPhone and Android touchscreen devices, has just hit the big 1.0.

                Правда с демками там тоже проблемы — допустим солитер на WebKit не заработл.
                  0
                  О! Спасибо, люблю я ExtJS, а тут ещё и такое от них же!

                  А как оно вообще работает на других телефонах? Как в опере мини?
                    +1
                    Наиболее адекватно работать под айфоном и андроидом версии от 2.1. На WM 6.5, Nokia Browser, Opera Mini и Opera Mobile не работает.
                      0
                      Обидно. А есть ли что-то для более удобной разработки страниц для WM 6.5, Nokia Browser, Opera Mini и Opera Mobile?
                0
                Еще есть XUI, кое что есть в YUI, Dojo.
                  0
                  Любопытно, спасибо. Жаль что нет демок. Вот доджо интересно, да.
                0
                Nokia 5530 (Opera Mobile) не очень:)
                  0
                  Попробовал на HTC Wildfire прошивка 2.1. Пробовал как на встроенном браузере так и на опере мини.
                  Так артефакты видны. Торможение есть. Ну и да еще не работает ни твиттер ни мап. так же отказывается работать кнопка Back. Мап отказался работать как при включенном ГПС так и при выключенном.
                    0
                    Все это хорошо, но даже на некоторых мобилах с броузерами А-класса будет работать с проблемами. В России же наибольшее распространение мобилы с броузерами классов Б и С.
                      0
                      К вопросу о совместимости.
                        0
                        А в настольных браузерах должно работать? Карта не заработала хотя и спросила разрешение на location, твиттер работает…
                          0
                          Был глюк со стилем, попробуйте сейчас.
                            0
                            linux chromium 8.x — OK
                            iphone 2g — OK, но пролистывание карты подтормаживает, то есть интерфейс не сразу срабатывает на движение пальцем… странно… гуглокарты работают мгновенно

                            ну еще непонятно зачем 20px-зазор вокруг карты)
                              0
                              вообще заметил, на 2G ВЕСЬ интерфейс срабатывает не мгновенно а после небольшого но одинакового лага для всех элементов (прокручивагие экрана, кнопка)

                              jquery таки тяжеловат?
                                0
                                Вполне может быть и такое, жаль если так =(
                                Кстати, попробуйте для сравнения запустить демки Sencha Touch. Сильно ли они будут тормозить?
                                  0
                                  трудно сказать, большинство приложений там для ipad а geocongress после вопроса о разрешении location вообще завис)))
                            0
                            В примере похоже кодировка UTF-8 с BOM, view source в Firefox показывает
                            п»ї<!doctype html>

                            это баг или фича?
                              0
                              Да, кодировка именно такая. И это скорее всего баг.
                                +1
                                поставьте кодировку UTF-8 без BOM и символ вылазить не будет.
                                и в htaccess в папку положите или добавьте строчку AddDefaultCharset UTF-8

                                А вообще одно время так напарился с этим jmobile, он настолько сырой… посоветовали добрые люди www.sencha.com/products/touch/download.php
                                не в пример стабильней и приятней.

                                А обзор хороший, не в пример документации у них на сайте.
                                  0
                                  Спасибо, так и сделаю!

                                  На сенче я тоже писал проект, достаточно навороченный, много своих стилей и собственных компонент. К сожалению, на момент написания проекта — август этого года — сенча жутко тормозила на айфоне. А вот на айпаде все было отлично.

                                  Кстати, я на основе этой документации и делал. Она на самом деле полная, просто не очень удобна в использовании — постоянно приходится куда-то перескакивать. Сейчас думаю над аналогичным постом по сенче, надеюсь выйдет дельным.
                                    0
                                    сейчас делаю на сенче — такие же проблемы у jtouch и jmobile на айпаде.
                                    Собственно это первый проект именно приложения (пусть и веб) под айпад. Столько ньюансов… жуть.
                                    Собственно на сенчу перешел из-за того что не смог заставить сайт открываться в одном окне на весь экран — решается вьювпортом+пара мета тегов, в т.ч. и тот, который отвечает за показ как приложение. в итоге получилось, что с ярлыка запускается на полный экран, но при переходе по любой ссылке — появляются панельки броузера + открывается в новом окне.
                              0
                              var shuffle = function(o){ //v1.0
                              	for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
                              		return o;
                                      };
                              

                              Большего надругательства над for я еще не видел…
                              Не считаете, что так лучше воспринимается?
                              var shuffle = function(o){ //v1.0
                                for(var j, x, i = o.length; i;);
                                {
                                   j = parseInt(Math.random() * i);
                                   x = o[--i];
                                   o[i] = o[j];
                                   o[j] = x;
                                }
                                return o;
                              };
                              
                                0
                                Не спорю, смотрится лучше, но данный пост все же направлен на показ функций по работе с jQM. Да и если смотреть минимизированные либы, то они вообще не воспринимаются.
                                  0
                                  Сужу по себе, меня заставил этот код задуматься «а в чем подвох» — не сразу заметил точку с запятой после for. Циклы с пустым блоком операторов большая редкость и плохая практика.
                                  Может тогда не стоило приводить этот код функции? К тому же, в статьях не приводят код в сжатом виде, если хотят, чтобы в нем разобрались другие.
                                0
                                Да, пожалуй вы правы, эта функция была лишней. Спасибо.

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое