Пользователь
0,0
рейтинг
14 мая 2015 в 04:13

Разработка → Быстрое кроссплатформенное HTML5 приложение на Framework7

Задумываясь о разработке html5 приложения, многим сразу на ум приходит jQuery, или точнее jQueryMobile. И попробовав написать даже самое простенькое приложение используя jQueryMobile, очень легко разочароваться, так как производительность и отзывчивость получившегося html5 приложения куда ниже ожидаемого, и уж совсем его не сравнить с нативными приложениями.



Соответственно, если продолжить идти по пути html5, вы постепенно узнаёте, что тормоза и плохая отзывчивость из-за того, что есть множество тонкостей, например, что jquery далеко не самый быстрый вариант для приложения или по-умолчанию любое нажатие пользователя срабатывает с 300мс задержкой, что ухудшает отзывчивость.

Также важным моментом является есть ли набор готовых типичных компонентов, таких как список, кнопки, боковое меню итд, время на повторную разработку которых нет смысла тратить. Можно добавить еще к этому списку то, что как-то всё таки нужно решить проблему производительности, чтобы конкурировать с нативными приложениями.

Framework7


И мы, наконец, подходим к самому главному, чтобы не забивать себе голову решением таких проблем, а получить сразу готовый инструмент для разработки быстрых, отзывчивых и функциональных html5 приложений, существует Framework7. Сам я с ним столкнулся совершенно случайно, и удивился тому, насколько он прост в использовании без необходимости искать решения в разных местах, достаточно просто подключить framework7.js.

Стоит отметить, что для работы с Framework7 не нужно использовать какие-то сторонние модули или библиотеки, так как он всё уже содержит:
  • High-performance Animation — хочется выделить это отдельно, так как анимации и правда очень быстрые
  • fast-clicks — решает проблему задержки 300мс без сторонних библиотек
  • Template7 — движок шаблонов, синтаксис как у Handlebars, но меньше весит и скорость до 3х раз быстрее
  • Dom7 — более быстрая и прозрачная замена jQuery
  • Navigation / Router — множество вариантов переходов и их контроля
  • Поддержка стилей, включая частичную поддержку material design
  • Огромный список встроенных компонентов, таких как forms, buttons, list view, pull to refresh, infinite scroll, slide menu итд
  • Свайпы — встроенные свайпы на все случаи жизни: вызвать меню свайпом, возврат к предыдущему экрану, удалить элемент итд
  • И множество других полезных вещей

На сайте есть огромное кол-во примеров (работают в браузере), инструкций и обучающих статей (например, работа Framework7 совместно с AngularJS)
www.idangero.us/framework7

Пример приложения




Чтобы далеко не ходить, создадим небольшое приложение-пример, где можно будет посмотреть, как объединить отдельные компоненты фреймворка в единое приложение. Будем использовать slide menu, pull to refresh, infinite scroll, смену material/ios style на лету и огромным списком на 8000 элементов, который не тормозит (virtual list).

Структура приложения довольно простая:
  • index.html — дизайн приложения
  • about.html — дизайн другого view
  • app.js — файл инициализации и настроек приложения
  • css/app.css — этот файл в общем-то не нужен, так как в framework7.css есть уже все настройки дизайна, но можно, например, сменить цвет фона бокового меню
  • lib/framework7.js — сам фреймворк
  • lib/framework7.css — дизайн всех элементов и компонентов в стиле ios
  • lib/framework7.material.css — дизайн всех элементов и компонентов в стиле material

Больше ничего не потребуется, другие библиотеки или фреймворки для создания приложения не нужны. Но при желании можно использовать require.js, angular.js, matreshka.js итд.

index.html
Для начала рассмотрим каркас index.html:
<!DOCTYPE html>
<html>
  <head>
    <!-- Добавляем необходимые meta-тэги -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <title>My App</title>
    <!-- подключаем framework7 стили, и добавляем id, чтобы можно было менять стиль на лету -->
    <link id="pagestyle" rel="stylesheet" href="lib/framework7.css">
    <!-- подключаем наши кастомные стили -->
    <link rel="stylesheet" href="css/app.css">
  </head>
  <body>
    <!-- statusbar-overlay для правильной поддержки полноэкранного режима -->
    <div class="statusbar-overlay"></div>
    <!-- тоже самое для panel -->
    <div class="panel-overlay"></div>

    <!-- если нужно левое боковое меню с reveal эффектом -->
    <div class="panel panel-left panel-reveal">
    </div>

    <!-- самое главное, добавляем views -->
    <div class="views">
    <!-- главный экран, должен содержать класс view-main -->
      <div class="view view-main">

    <!-- если требуется верхняя панель, так же указываем что у нее будет белая тема -->
        <div class="navbar theme-white">
        </div>

    <!-- собственно содержимое страницы, указываем что navbar и toolbar будет зафиксированы -->
        <div class="pages navbar-through toolbar-through">
    <!-- в data-page указываем название страницы, которое желательно для всех страниц быть разным -->
          <div data-page="index" class="page">
            <div class="page-content">
            </div>
          </div>
        </div>

    <!-- если нужная нижняя панель -->
        <div class="toolbar">
          <div class="toolbar-inner">
          </div>
        </div>
      </div>

    </div>
    <!-- подключаем framework7 и наш файл инициализации -->
    <script type="text/javascript" src="lib/framework7.js"></script>
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>            

Добавление компонентов очень просто реализовано (для каждого компонента есть инструкция на сайте), например, чтобы добавить pull-to-refresh, достаточно добавить в
<div class="page-content">
</div>

класс pull-to-refresh-content, и дизайн стрелочки, которая будет показываться при обновлении:
<div class="page-content pull-to-refresh-content">
  <div class="pull-to-refresh-layer">
      <div class="preloader"></div>
      <div class="pull-to-refresh-arrow"></div>
  </div>
</div>

Теперь надо добавить table view (list view), в котором будет список наших элементов. Для создания коротких списков подойдет List View (Media List итд, список можно создавать статически или динамически):
<div class="list-block media-list"><ul>тут данные</ul></div>

Но для очень длинных списков требуется выгрузка элементов, которые сейчас не видны на экране, это необходимо для того, чтобы ничего не тормозило, и приложение работало как и нативное. Такий список называется Virtual List, и создается так же просто:
<div class="list-block virtual-list media-list">тут оставить пусто</div>

В дальнейшем список надо будет проинициализировать и заполнить в app.js

Сюда же добавим infinite-scroll, который добавляет так же, добавлением одноименного класса, дизайна крутилки и указанием начиная с какого расстояния вызывать infinite-scroll:
<div class="page-content pull-to-refresh-content infinite-scroll" data-distance="100">
		<div class="pull-to-refresh-layer">
		    <div class="preloader"></div>
		    <div class="pull-to-refresh-arrow"></div>
		</div>

		<div class="list-block virtual-list media-list"></div>

		<div class="infinite-scroll-preloader">
		  <div class="preloader"></div>
		</div>
</div>


Чтобы сменить ios стиль на material стиль и наоборот, добавим 2 кнопки, например, в левом меню:
<div class="list-block left-menu">
         	<div class="row theme-white" style="width:90%;margin-left: auto;margin-right: auto;">
		  <div class="col-50">
		    <a href="#" class="button changestyle" rel="lib/framework7.css">iOS style</a>
		  </div>
		  <div class="col-50">
		    <a href="#" class="button changestyle" rel="lib/framework7.material.css">Android style</a>
		  </div>
		</div>    
</div>

Позже на класс changestyle повесим обработчик, чтобы реагировал на нажатие и менял css файл на указанный в rel.

app.js
Теперь рассмотрим файл app.js, в котором производится настройка приложения, инициализация списков итд.
// Инициализируем движок фреймворка
var myApp = new Framework7({
    animateNavBackIcon:true, 
    pushState: true, //при переходе между экранами, чтобы работала кнопка back на android
    modalTitle: "MyApp",
    modalButtonCancel: "Отмена", //текст Cancel кнопки
    swipePanel: 'left', //включаем левого меню свайпом
});

// если запускается на ios, то кнопки back нету, и поэтому можно отключить
if (Framework7.prototype.device.os == "ios") 
	myApp.params.pushState = false; 
 
// вместо jQuery используем встроенный Dom7, переменную можно назвать $, чтобы было привычнее, но если оставить $$, то в дальнейшем можно будет легко подключить jQuery, если понадобится
var $$ = Dom7;

// по клику меняем css файл, меняя ios и material стиль. Выбор запоминаем в localStorage, чтобы при перезапуске приложения загружался нужный css
$$(".changestyle").click(function() { 
	$$("#pagestyle").attr("href",$$(this).attr('rel'));
	localStorage.setItem("css", $$(this).attr('rel'));
	return false;
});

// при первой загрузке загружаем запомненный css
if(localStorage.getItem("css")) {
	$$("#pagestyle").attr("href",localStorage.getItem("css"));
}

// инициализируем главную вьюху
var mainView = myApp.addView('.view-main', {
  dynamicNavbar: true, 
  domCache: true, //чтобы навигация работала без сбоев и с запоминанием scroll position в длинных списках
});

// инициализируем и заполняем вирутальный список используя шаблон (один из вариантов использования Template7)
var myList = myApp.virtualList('.list-block.virtual-list', {
    items: [
        {
	    id: 1,
            title: 'Item 1',
            picture: 'http://lorempixel.com/88/88/abstract/1'
        },
        {
	    id: 2,
            title: 'Item 2',
            picture: 'http://lorempixel.com/88/88/abstract/2'
        }
    ],
    height:44,
	template: 
		'<li class="contact-item" data-id="{{id}}" >' +
			  '<a href="about.html" class="item-link">' + 
				  '<div class="item-content">' +
			                  '<div class="item-media"><img src="{{picture}}" width="22"></div>' +
			                  '<div class="item-inner">' +
			                      '<div class="item-title">{{title}}</div>' +
			                  '</div>' +
	        	          '</div>' +
		 	  '</a>' + 
               '</li>'
});  

// пример функции, которая будет обновлять содержимое виртуального списка
function reloadTable(table, array)
{
	table.items = array;
	table.update();
}

// заполним виртуальный лист 20 новыми элементами
var itemsArray = [];
function firstInitList(text, count)
{
	itemsArray = [];
	for (var i = 0; i < count; i++ ) 
	{
		itemsArray.push({ id: i, title: text + ' ' + i, picture: 'http://lorempixel.com/88/88/abstract/' + i });
	}
}

firstInitList("Item", 20);
reloadTable(myList, itemsArray);

// инициализируем pull-to-refresh
var ptrContent = $$('.pull-to-refresh-content');
 
ptrContent.on('refresh', function (e) {
    // Эмулируем 0.5секундную задержку
    setTimeout(function () {
	refreshIt();
    }, 500);
});

// просто случайные данные для генерации виртуального листа
var authors = ['Beatles', 'Queen', 'Michael Jackson', 'Red Hot Chili Peppers'];

function refreshIt()
{
        // первые 10 элементов создадим с надписью Refresh
	firstInitList("Refresh", 10);
	myList.deleteAllItems();
	myList.appendItems(itemsArray);

        // остальные 8000 случайным образом
	var temparr = [];
	for(var i = 0; i<8000; i++) 
	{
            var picURL = 'http://lorempixel.com/88/88/abstract/' + Math.round(Math.random() * 10);
            var author = authors[Math.floor(Math.random() * authors.length)];
	    temparr.push({ id: i, title: author, picture: picURL });
	}
        myList.appendItems(temparr);
        myApp.pullToRefreshDone();
}

// инициализируем infinite-scroll
$$('.infinite-scroll').on('infinite', function () { 
  loadMore(); 
});          

// флаг
var loading = false;

//прячем крутилку infinite-scroll'а
$$('.infinite-scroll-preloader').hide();

function loadMore()
{
  // если уже загружаем данные, то ничего не делаем
  if (loading) return;
  $$('.infinite-scroll-preloader').show();
 
  // Эмулируем 1 секундную задержку
  setTimeout(function () {
    for (var i = lastIndex + 1; i <= lastIndex + itemsPerLoad; i++) {
	itemsArray.push({ id: i, title: 'Item ' + i, picture: 'http://lorempixel.com/88/88/abstract/1' });
    }
    reloadTable(myList, itemsArray);
    // сбрасываем флаг, после загрузки данных
    loading = true; 
  }, 1000);
}


app.css
// дизайн крутилки для infinite-scroll
.infinite-scroll-preloader {
  margin-top:-20px;
  margin-bottom: 10px;
  text-align: center;
}
.infinite-scroll-preloader .preloader {
  width:34px;
  height:34px;
}  
// сменим цвет фона navbar
.navbar {
  border-bottom: none;
  background: #2196f3;
  color: #ffffff;
}
.navbar a.link {
  color: #ffffff;
}
// сменить цвет фона левого меню
.panel, .left-menu .list-button {
  background-color: #3f4041;
}
.left-menu .item-link.list-button {
  text-align: left;
}


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

Ускоряем html5 приложения на старых версия android. Crosswalk


Хоть у нас и получилось очень быстрое и легкое приложение, на старых версиях андроид оно всё равно будет недостаточно производительным.

Дело в том, что на версиях андроид до 4.4 используется очень тормозной webview (убедиться в этом можно, например, если на 4.1 андроид поставить chrome beta и запустить приложение в нём, а потом сравнить с тем, что есть во встроенном браузере, то разница в скорости будет очень заметна). Поэтому, если просто запаковать html5 приложение в apk, оно будет использовать именно встроенный тормозной webview.

Только начиная с 5.x андроида, webview обновляется отдельно и базируется на свежем chromium, благодаря чему html5 приложение будет работать быстро и плавно.

Проще говоря, если нужна хорошая производительность от html5 приложения на любых устройствах и любых версиях андроид, нужно чтобы оно работало на chromium движке. Проект, который позволяет это сделать, называется crosswalk и вместо встроенного webview используется свой собственный, который работает на последней версии chromium.



Самый простой способ проверить как ваше html5 приложение будет работать с использованием crosswalk, это установить Intel XDK, создать пустой «Standart HTML5» проект, и заменить в созданном проекте папку www на вашу.

После этого выбрать Build и нажать на Crosswalk for Android. Приложение будет скомпилировано на удаленном сервере, и спустя несколько минут вы получите ссылку на apk (версия для arm и x86). К минусам можно отнести тот факт, то размер приложения увеличится на ~19мб.

Сайт framework7: www.idangero.us/framework7
Онлайн пример готового приложения: comedian-ant-73047.bitballoon.com (так как онлайн, то немного тормозит загрузка стилей)
Исходники: yadi.sk/d/Quu2VfApgcGXA
Готовые apk файлы, созданные через Intel XDK: yadi.sk/d/marrZA5-gcGuQ

Онлайн пример большинства возможностей (kitchen-sink): framework7.io/kitchen-sink-ios или framework7.io/kitchen-sink-material
Тоже самое в material дизайне: poacher-bear-12003.bitballoon.com/kitchen-sink-material/index.html
@Shannon
карма
19,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (20)

  • +3
    Таких множество — мне понравился onsen.io и goratchet.com Последнии прижился как основной, на нем все и разрабатываю.
    • +2
      Возможно мой пример плохо отобразил все возможности framework7, поэтому в конец статьи добавил ссылки на kitchen-sink (отдельно в material дизайне), с почти (много чего добавляется и не успевает попасть в kitchen-sink, но даже и то что сейчас добавлено впечатляет) полным перечнем возможностей собранных в одном приложении от автора

      Тут всё таки стоит добавить, что по числу готовых компонентов (что для меня оказалось решаюшив фактором в пользу framework7 вместо ratchet), разнообразных killer features, и даже подробной и удобной документации, аутентичности анимаций, и результирующей скорости приложения — framework7 оказался пока вне конкуренции среди подобных фреймворков
  • +1
    Спасибо за статью. Очень интересно и главное во время, как раз пришла задача по разработке приложения на phoneGap, думаю попробую этот фреймворк7.
  • 0
    Подскажите, есть ли и какие ограничения по объёму WebSql?
    • 0
      Ограничение есть и довольно жесткое, точно не вспомню какое, но его можно обойти с помощью SQLite-Cordova-Plugin
  • +1
    Спасибо! Фреймворк мне как таковой оказался не очень интересен, но узнал про Intel XDK. Век живи — век учись!
    • +1
      А что вы используете и почему фреймворк оказался неинтересн?
      • +1
        Пообщался с командой, сказали что я дурак и штука нужная )) Надо наверное на примерах попробовать.
  • +1
    Спасибо, надо будет глянуть. Плотно использовал onsen, но этот, похоже и пошустрее и плюшками радует. Раздел «killer features» на сайте впечатлил.
  • 0
    Подскажите, а сформировать apk-файл можно только через Intel XDK?
    А ipa-файл чем можно сделать?
    • 0
      Cordova/Phonegap
  • 0
    поосторожнее там с демками, demo приложение Chattr похоже взломано, выдает алерт на украинском и редиректит на порно сайт
    • 0
      Может это фича?) Для привлечения внимания, например?
  • 0
    Странно, что никто не упомянул про более популярный Ionic Framework, инфраструктура которого гораздо богаче.
    • 0
    • +1
      У framework7 более полный набор компонентов и они более идентичны со стилем ios 9, чем варианты от ionic
      Так же после некоторых экспериментов с ionic, он переодически подлагивает на ios (в android версии это менее заметно)
  • 0
    Framework7 очень хорош. Однако в предлагаемых шаблонах IOS и Material есть неприятная вещь — это скролл, залезающий под фиксированные панели. Если содержимого очень много, может получиться так, что при прокрутке страницы: скролла вообще не будет видно до определенного момента. Вот пример (для наглядности верхнюю панельку сделал полупрозрачной), баг наблюдался в Android и в IOS в хроме.

    Это могло стать причиной выбора другого фрейморка, так как хочется остановиться на лучшем и работать уже с ним.
    Мне очень понравилась событийная модель этого фреймворка, поэтому я нашел решение этой проблемы в замене padding на margin в стилях к контенту с фиксированными панельками, так же необходимо изменить свойство height: calc(100% — NNpx), где NNpx — резамеры вертикальных отступов margin.
    • 0
      Найден еще один баг: если открыть несколько окон с сообщением (myApp.alert('Message')), а затем закрыть одно из них — пропадает подложка сообщений (затемняющий фон).

      Еще более неприятным стало то, что метод myApp.hidePreloader() — скрывает все такие окна с сообщениями.
      • +2
        Напишите автору об ошибках либо сюда, либо сюда:
        https://github.com/nolimits4web/framework7/issues
        http://forum.framework7.io/#!/bugs-and-issues

        Подобные баги обычно легко исправляются

        • +1
          Да, некоторое время назад уже писал им: scroll-bag

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