Javascript for mobile devices
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Javascript for mobile devices

on

  • 2,505 views

 

Statistics

Views

Total Views
2,505
Views on SlideShare
2,397
Embed Views
108

Actions

Likes
2
Downloads
13
Comments
0

5 Embeds 108

http://ykhrustalev.github.com 80
http://www.linkedin.com 14
http://ykhrustalev.github.io 8
https://www.linkedin.com 5
http://nodeslide.herokuapp.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Javascript for mobile devices Presentation Transcript

  • 1. JS в мобильных устройствах На примере одного проекта
  • 2. ПредставлюсьЮрий Хрусталев, инженер в DataArtyuri.khrustalev@dataart.comhttp://about.me/ykhrustalevhttp://dataart.com
  • 3. Проект• Задача o R&D / Поиск истины – Пригоден ли html5 для использования на мобильных устройствах – UI фреймворк для сайтов заказчика o Сделать демо новостного сайта• Требования o Поддержка наибольшего числа устройств o Простота o Гибкость
  • 4. Все уже сделано, но не нами http://ft.com*источник http://aspirelondon.com/blog/articles/financial-times-app/ft-ipad-app/
  • 5. Чем пользуются в mobile web?• Мобильный телефон• Планшетный компьютер• Читалка• Плеер
  • 6. Через что смотрят mobile web? Webkit браузеры доминируют*источник: http://en.wikipedia.org/wiki/Mobile_operating_system
  • 7. Типичные характеристики• Устройство o Слабая батарейка o Не всегда много памяти o Дорогой интернет (спорно) o Размер экрана в среднем меньше десктопа• Браузер o Ограничен в памяти o Получает системные события не первый o Частично поддерживает новые стандарты
  • 8. Мобильный браузер• Dom API• Хранилище на стороне клиента• Анимация• Аудио, Видео• Canvas• SVG• WebSocket• WebWorkers• ...
  • 9. Проверка возможностейhttp://html5test.com/http://haz.io/http://caniuse.com/
  • 10. Требования к демо сайту• Мокапы o Много картинок в интерфейсе (20 x 10) o Много видео o Все скролится (10 скролов) o Кругом одни слайдшоу (20 слайд шоу)• Дополнительно o Оффлайн режим o Бекэнд постоянно падает o Закладываться на новые устройства
  • 11. Выбор каркаса фреймворка• jquery / jquery mobile o Компоненты – плагины o Нет каркасности• sencha touch / kendo o Есть все (почти) o Лицензия• Backbone o Только MVC o Ничего не навязывает o Нет UI компонентов
  • 12. Слайдеры и скролеры• iScroll• TouchScroll• Wipetouch• Touchswipe• Scrollability• touch-scroll• Zynga Scroller• -webkit-overflow-scrolling:touch;
  • 13. Пишем свой фремворк• Быстрый• Потребляет мало памяти• Кросс браузерный• Гибкий• Слабо связанный
  • 14. Что мы хотели
  • 15. JS рутина• DOM o Селекторы• Array o delete arr[0] o Фильтрация• Object o Итерирование o Наследование• События• Логирование
  • 16. DOM• Jquery o Большой o Известный o Кросбраузерный• Zepto o Легкий o Ориентирован на mobile
  • 17. DOM• css3 селекторы o querySelector() o querySelectorAll()• fragments var div = document.getElementsByTagName("div"); var fragment = document.createDocumentFragment(); for ( var e = 0; e < elems.length; e++ ) { fragment.appendChild( elems[e] ); } for ( var i = 0; i < div.length; i++ ) { div[i].appendChild( fragment.cloneNode(true) ); }
  • 18. Утилиты• Underscore o Легкий o Но только хелперы• Backbone – Коллекции – Диспетчер событий – Модели – Представления – Контроллеры
  • 19. Необходимо невелировать среду• Поддержка ECMA5• CSS• Анимация• Системные события
  • 20. Патерны: Singletonvar instance = (function () { var privateVar; function privateMethod() { // ... } return { // public interface publicMethod: function () { // private members can beaccessed here } };})();
  • 21. Паттерны: Mixin, Inheritance• Прототип o Динамическое изменение поведения всех объектов o Конструктор• Примесь o Копирование поведения
  • 22. Определяем среду исполненияvar ua =navigator.userAgent.toLowerCase().replace(/(.*?)/g, "");var devices = { "android": /androids+([d.]+)/, "opera" : /opera.+(presto/[^.]+.[^.]+)/, "ipad" : /ipad.*oss([d_]+)/, "kindle" : /kindle|silk/};for(i in devices) { if (devices.hasOwnProperty(i)) { var matches = devices[i].test(ua); // .. }}
  • 23. Touch событияvar hasTouch = ontouchstart in window;var Events = { hasTouch : hasTouch, resizeEvent : (onorientationchange in window ) ? orientationchange : resize, clickEvent : hasTouch ? tap : click, // синтетическое startEvent : hasTouch ? touchstart : mousedown, // один раз moveEvent : hasTouch ? touchmove : mousemove, // постоянно endEvent : hasTouch ? touchend : mouseup, // один раз cancelEvent : hasTouch ? touchcancel : mouseup,};// webkitEvents.transitionEndEvent = webkitTransitionEnd;
  • 24. Паттерны: Abstract Factoryvar device = ipad; // androidvar Environment = (function(device) { var environment; switch(device) { case ipad : environment = ... break; ... } environment = _({}).defaults(environment); return { factory : function() { return environment; } }})(device);var environment = Environment.factory();
  • 25. Дебаг и логирование• "use strict" o Подсветка в IDE• Профилирование важно o Замена дебагеру o Поиск узких мест• console.log() o В ipad консоль не раскрывает объекты o Снижает производительность o Не так удобно как хотелось бы
  • 26. Профайлер• Идея log4j o Каждый компонент пишет в своем namespace o Уровни логов (debug, info, warn)• Общий пул сообщений o warn в одном месте может показать состояние всей системы o Альтернатива стек трейсу• Возможность выключить все логи• Возможность смотреть логи в production
  • 27. События приложения• Приложение event-driven• Компоненты знают мало друг о друге• Многие вещи происходят асинхронно o Ajax o Анимация o DOM изменения• События управляют объектами
  • 28. Диспетчер событийfunction EventDispatcher() { this._events = {};}EventDispatcher.prototype = { on: function (name, handler, scope) { this._events[name] = this._events[name] || []; this._events[name].push({ handler: handler, scope: scope || this }); }, fire: function (name) { var args = arguments.toArray().slice(1), events = this._events[name]; if (events) { events.forEach(function (event) { event.handler.apply(event.scope, args); }); } }};
  • 29. Анимация• translate• translate3d• scale• rotate• Хардварная• CSS префикс• Скорость может отличаться
  • 30. Анимация в деталях• CSS .container { -webkit-transform: translate3d(0px, -700px, 0px); -webkit-transition: all 10s cubic-bezier(0, 0, 0.1, 1); -webkit-transform-style: preserve-3d; }• Jquery/Zepto $(.container).animate({ translate3d: translate3d(0px, -700px, 0px), }, 10);
  • 31. Скорость анимации• Не грузите контент• Не меняйте DOM• Избегайте любых действий во время анимации• translate3d работает только на видимых обхектах• Меняйте DOM только после остановки анимации• Много анимации может привести к падению браузера
  • 32. Скрол• Хуки в процесс анимации• Управление touch событиями• Управление через его API• Синхронизация с другими компонентами• Ускорение• Обработка смены ориентации экрана• Отзывчивый интерфейс
  • 33. Слайдшоу• Ленивое построение слайдов• Экономия памяти• Хуки в процесс анимации• Автослайдинг• Переход на произвольный слайд• Отзывчивый итерфейс
  • 34. Особенности на устройствах• Ipad баг: событие окончания анимации пропускается в ~20% случаев o использовать планировщик• Android при разворотах кидает и "resize" и "orientationchange" o Отлавливать оба события• Android работает медленнее с translate3d при включенном "OpenGL acceleration" o Android WebView
  • 35. Особенности на устройствах• Контейнер не отпускает "move” при выпадении из поля видимости – Прокси для touch событий• Изменение ориентации приводит к перерисовке интерфейса – Быть готовым и обрабатывать корректно• Синхронизация анимации при новых касания – Уметь останавливать анимацию и начинать новую
  • 36. Смена ориентацииwindow.addEventListener(orientationchange, function() { var d = Math.abs(window.orientation); if (d == 90) { // пейзаж } else { // портрет }}, false);• На Android событие resize
  • 37. Планировщикvar Scheduler = function () { this.callbacks = []; this.timers = [];};Scheduler.prototype = { schedule: function (callback, delay) { var self = this; self.callbacks.push(callback); var timer = setTimeout(function () { self.execute(); }, delay); self.timers.push(timer); }, execute: function () { var callbacks = this.callbacks; if (callbacks && callbacks.length) { var cb; while (cb = callbacks.shift()) { cb(); } } }};
  • 38. Синхронизация анимации• Автослайдинг Proxy контейнер для делегирования событий на активный слайд Visible Screen Scrollable Y Scrollable Y Slide Slide 1 2
  • 39. Синхронизация анимации• Текущее положение анимируемого контейнераvar computedStyle = window.getComputedStyle(node)[-webkit-transform];var parsedMatrix = new WebKitCSSMatrix(computedStyle);var x = parsedMatrix.e;var y = parsedMatrix.f;• При смене ориентации необходимо пересчитывать размеры
  • 40. Навигация в приложении• Url fragment # o http://app.example.com#account o http://app.example.com#news• Подписка событий на изменение url window.addEventListener("hashchange", function () { var router = window.location.hash; // ... }); function navigate(route) { window.location.hash = route; }• Изменение hash медленная операция
  • 41. Хранилище на стороне клиента• до 50 мб (требует подтверждения пользователя)• Local storage• App cache• Indexed DB• Websql (не является стандартом)• Cookies
  • 42. Хранилище на стороне клиента• local storage localStorage.key = value• app cache <html manifest="app.appcache"> #app.appcache CACHE MANIFEST index.html css/main.css js/app.js
  • 43. Обновления• Обновление файлов из манифеста var cache = window["applicationCache"]; cache.addEventListener(updateready, function () { window.location.reload(); });• Чистка локального хранилища localStorage.clear();• Получение свежих файлов o запросить http://app.example.com/file?{timestamp}
  • 44. Аудио, Видео• тег video• <video controls autoplay preload src="video.mp4"></video> тег audio <audio controls autoplay preload loop src="audio.wav">• Формат у всех свой• Процессор у всех разный• Спеки лучший друг• Готовим контент на сервере
  • 45. Шаблоны• Обрабатываются на клиенте• Удобные для верстки• Понятные для браузера• Быстрые в обработке• XSS
  • 46. Шаблонизаторы• Mustache – язык шаблонов• Реализация • dust.js • hogan.js• Серверный компилятор o node.js
  • 47. Компиляция шаблонов• Сервер <ul> {#messages} <li data-id="{id}">{text}</li> {/messages} </ul> o Распарсить шаблон o Скомпилировать в JS представление• Клиент o Вставить данные o Обновить html• Внутренне представление шаблона o Конкатенация JS строк
  • 48. Отрисовка HTML• Работа с DOM может быть дорогой o Reflow – пересчет параметров дерева o Repaint – перерисовка старницы• Как избежать o Fragments o Большие части лучше менять innerHtml o Маленькие изменения напрямую через DOM
  • 49. Собираем все вместе• Браузер загружает файлы асинхронно• Велика вероятность конфликта зависимостей• Глобальная область видимости• Модульная архитектура• Выход есть o Инъекция зависиммостей o Компиляция всего приложения
  • 50. Require.js• Поддерживает минификацию o JS o CSS• Умеет грузить файлы по порядку• Помогает избегать конфликтов имен• Работает с node.js
  • 51. Require.js<!DOCTYPE html><html manifest="app.minifest"> <head></head> <body> <script src="js/require.js" data-main="js/application"></script> </body></html>
  • 52. Require.js// spec.jsrequire.config({ paths: { "zepto": "vendor/zepto", "logger": "lib/logger", "environment": "lib/environment", ... }});
  • 53. Require.js// application.jsdefine([ "order!zepto", // соблюдает порядок "logger"], function ($, Logger) { var logger = new Logger; // ...});
  • 54. Производительность• Профилирование• Быстрые операции o Математические расчеты o Запросы к DOM o Оперирование объектами• Медленные операции o Изменения в DOM o Отрисовка• Компиляция шаблонов• Минификация CSS, JS• Освобождение ресурсов
  • 55. Память• Потребители памяти – Картинки – DOM дерево – Анимация• Если память кончится, браузер упадет• Меры борьбы – Прятать все, что не видно пользователю – Используем бекграундные картинки вместо <img> – Избегать reflow/repaint, особенно при анимации – Избавляться от тяжелых библиотек
  • 56. Интеграция с бекэндом• Минимизируем число http запросов o Запрос всех картинок одним запросом o Кодирование картинок в base 64• JSON/ GZIP• Подготовка контента o Изменение размеров картинок под устройство• Application cache• Чем меньше логики на клиенте - тем лучше
  • 57. Делаем свою Карусель
  • 58. Требования• Карусель картинок• Работоспособность в ipad, chrome• Поддержка событий мышки• Режим слайдшоу• Плавная анимация
  • 59. Контейнеры• Прокрутка осуществляется на контейнере, содержащем слайды• Показываем только видимые элементы• Контейнеры вне зоны видимости скрываем для экономии ресурсов
  • 60. Следим за браузером• touchStart - один раз• touchMove - много раз• touchEnd - один раз• transitionEnd – по окончании анимации• resize/orientationchange - смена ориентации• Не забываем про разницу chrome и ipad o В chrome перенос мышки на новую позицию вызывает "move"
  • 61. API• setSlideShowState(state)• moveNext()• movePrevious()• reset()
  • 62. Запрещаем zoom<meta name="viewport" content="width=device-width, initial-scale=1, maximum- scale=1, minimum-scale=1, user-scalable=no"/>
  • 63. Конструктор• Параметры по умолчанию• Навешивает DOM события• Делает все расчеты позиционирования o Окна просмотра o Слайдов• Сохраняет ссылки на слайды
  • 64. Обработчик браузерных событийScroll.prototype = { handleEvent: function (e) { switch (e.type) { case startEvent: this._startTouch(e); break; case moveEvent: this._moveTouch(e); break; case endEvent: this._endTouch(e); break; case resizeEvent: this._resize(e); break; case transitionEndEvent: this._transitionEnd(e); break; } return false; }}
  • 65. Алгоритм слайдинга• Вылавливае "start"• Запоминаем начальную точку• Следим за событием "move"• Передвигаем контейнер слайдов• По событию "end" проверяем нужно ли осуществить полный слайд или вернуть в исходное положение• Блокируем объект до окончания анимации
  • 66. Алгоритм слайдшоу• Создаем вызов для слайдинга• В момент исполнения вызова проверяем состояние слайдшоу (true/false) o true - moveNext() o false - ничего o В момент анимации блокируем объект• При достижении границы переходим на первый слайд
  • 67. Узкие места• Потеря состояния начала движения• Потеря события "transitionEnd" (ipad bug)• Некорректная обработка смены ориентации
  • 68. КонтактыЮрий Хрусталев, инженер в DataArtyuri.khrustalev@dataart.comhttp://about.me/ykhrustalev