Глава 11. Hyperview: мобильная гипермедиа
Вас можно простить за то, что вы думаете, что архитектура гипермедиа является синонимом Интернета, веб-браузеров и HTML. Без сомнения, Интернет — это крупнейшая система гипермедиа, а веб-браузеры — самый популярный клиент гипермедиа. Доминирование Интернета в дискуссиях о гипермедиа позволяет легко забыть, что гипермедиа — это общая концепция, которую можно применять ко всем типам платформ и приложений. В этой главе мы увидим архитектуру гипермедиа, примененную к не-веб-платформе: собственным мобильным приложениям.
Мобильная платформа как платформа имеет другие ограничения, чем Интернет. Это требует различных компромиссов и дизайнерских решений. Тем не менее, концепции гипермедиа, HATEOAS и REST можно напрямую применять для создания восхитительных мобильных приложений.
В этой главе мы рассмотрим недостатки текущего состояния разработки мобильных приложений и то, как архитектура гипермедиа может решить эти проблемы. Затем мы рассмотрим путь к гипермедиа на мобильных устройствах: Hyperview, платформу мобильных приложений, использующую архитектуру гипермедиа. В заключение мы дадим обзор HXML, формата гипермедиа, используемого Hyperview.
Состояние разработки мобильных приложений
Прежде чем мы сможем обсудить, как применять гипермедиа к мобильным платформам, нам необходимо понять, как обычно создаются собственные мобильные приложения. Я использую слово «родной» для обозначения кода, написанного на основе SDK, предоставляемого операционной системой телефона (обычно Android или iOS). Этот код упаковывается в исполняемый двоичный файл, загружается и утверждается в магазинах приложений, контролируемых Google и Apple. Когда пользователи устанавливают или обновляют приложение, они загружают этот исполняемый файл и запускают код непосредственно в ОС своего устройства. В этом смысле мобильные приложения имеют много общего со старыми настольными приложениями для Mac, Windows или Linux. Есть одно важное различие между настольными приложениями для ПК прошлых лет и сегодняшними мобильными приложениями. Сегодня почти все мобильные приложения являются «сетевыми». По сети, мы имеем в виду, что приложению необходимо читать и записывать данные через Интернет, чтобы обеспечить свою основную функциональность. Другими словами, сетевое мобильное приложение должно реализовать архитектуру клиент-сервер.
При реализации клиент-серверной архитектуры разработчику необходимо принять решение: должно ли приложение быть спроектировано как тонкий или толстый клиент? Нынешние мобильные экосистемы настоятельно подталкивают разработчиков к подходу с «толстым клиентом». Почему? Помните, что Android и iOS требуют, чтобы собственное мобильное приложение было упаковано и распространялось в виде исполняемого двоичного файла. Обойти это невозможно. Поскольку разработчику необходимо написать код для упаковки в исполняемый файл, кажется логичным реализовать часть логики приложения в этом коде. Код также может инициировать HTTP-вызовы к серверу для получения данных, а затем отображать эти данные с помощью библиотек пользовательского интерфейса платформы. Таким образом, разработчики естественным образом приходят к шаблону толстого клиента, который выглядит примерно так:
Клиент содержит код для отправки запросов API на сервер и код для перевода этих ответов в обновления пользовательского интерфейса.
Сервер реализует HTTP API, который поддерживает JSON и мало что знает о состоянии клиента.
Как и в случае с SPA в Интернете, у этой архитектуры есть большой недостаток: логика приложения распространяется на клиент и сервер. Иногда это означает, что логика дублируется (например, проверка данных формы). В других случаях клиент и сервер реализуют непересекающиеся части общей логики приложения. Чтобы понять, что делает приложение, разработчику необходимо проследить взаимодействие между двумя совершенно разными базами кода.
Есть еще один недостаток, который затрагивает мобильные приложения больше, чем SPA: отток API. Помните, что магазины приложений контролируют распространение и обновление вашего приложения. Пользователи могут даже контролировать, будут ли они получать обновленные версии вашего приложения и когда это произойдет. Как мобильный разработчик, вы не можете предполагать, что каждый пользователь будет использовать последнюю версию вашего приложения. Код вашего внешнего интерфейса фрагментируется по многим версиям, и теперь ваш серверный интерфейс должен поддерживать их все.
Гипермедиа для мобильных приложений
Мы увидели, что архитектура гипермедиа может устранить недостатки SPA в сети. Но может ли гипермедиа работать и для мобильных приложений? Ответ – да!
Как и в Интернете, мы можем использовать форматы гипермедиа на мобильных устройствах и позволить им служить двигателем состояния приложения. Вся логика контролируется из серверной части, а не распределяется между двумя базами кода. Архитектура гипермедиа также решает раздражающую проблему смены API в мобильных приложениях. Поскольку серверная часть предоставляет ответ гипермедиа, содержащий как данные, так и действия, данные и пользовательский интерфейс не могут рассинхронизироваться. Больше не нужно беспокоиться об обратной совместимости или поддержке нескольких версий API.
Итак, как вы можете использовать гипермедиа для своего мобильного приложения? Сегодня существует два подхода к использованию гипермедиа для создания и распространения собственных мобильных приложений:
Веб-представления, которые оборачивают надежную веб-платформу в оболочку мобильного приложения.
Hyperview, новая гипермедийная система, которую мы разработали специально для мобильных приложений.
Веб-просмотры
Самый простой способ использовать архитектуру гипермедиа на мобильных устройствах — использовать веб-технологии. SDK для Android и iOS предоставляют «веб-представления»: веб-браузеры без Chrome, которые можно встраивать в собственные приложения. Такие инструменты, как Apache Cordova, позволяют легко получить URL-адрес веб-сайта и создать собственные приложения для iOS и Android на основе веб-представлений. Если у вас уже есть адаптивное веб-приложение, вы можете бесплатно получить «родное» мобильное HDA. Звучит слишком хорошо, чтобы быть правдой, не так ли?
Конечно, у этого подхода есть фундаментальное ограничение. Веб-платформа и мобильные платформы имеют разные возможности и соглашения UX. HTML изначально не поддерживает общие шаблоны пользовательского интерфейса мобильных приложений. Одно из самых больших различий заключается в том, как каждая платформа обрабатывает навигацию. В Интернете навигация основана на страницах: одна страница заменяет другую, а браузер предоставляет кнопки «назад» и «вперед» для навигации по истории страниц. На мобильных устройствах навигация более сложна и настроена на физическое взаимодействие на основе жестов.
Для детализации экраны накладываются друг на друга, образуя стопки экранов.
Панели вкладок в верхней или нижней части приложения позволяют переключаться между различными стеками экранов.
Модальные окна выдвигаются вверх из нижней части приложения, закрывая другие стопки и панель вкладок.
В отличие от веб-страниц, все эти экраны по-прежнему присутствуют в памяти, отображаются и обновляются в зависимости от состояния приложения.
Архитектура навигации является основным отличием между функционированием мобильных и веб-приложений. Но это не единственный случай. Многие другие шаблоны UX присутствуют в мобильных приложениях, но не поддерживаются в Интернете:
pull-to-refresh для обновления содержимого на экране
горизонтальный свайп по элементам пользовательского интерфейса, чтобы отобразить действия
секционированные списки с прикрепленными заголовками
Хотя эти взаимодействия изначально не поддерживаются веб-браузерами, их можно моделировать с помощью JS-библиотек. Конечно, эти библиотеки никогда не будут иметь такого же ощущения и производительности, как нативные жесты. И их использование обычно требует использования архитектуры SPA с большим количеством JS, такой как React. Это возвращает нас на точку 1! Чтобы избежать использования типичной архитектуры «толстого клиента» собственных мобильных приложений, мы обратились к веб-представлению. Веб-представление позволяет нам использовать старый добрый HTML на основе гипермедиа. Но чтобы получить желаемый внешний вид мобильного приложения, нам приходится создавать SPA на JS, теряя при этом преимущества Hypermedia.
Чтобы создать мобильное HDA, которое действует и ощущается как нативное приложение, HTML не поможет. Нам нужен формат, предназначенный для представления взаимодействий и шаблонов собственных мобильных приложений. Это именно то, что делает Hyperview.
Гиперпросмотр
Hyperview — это гипермедийная система с открытым исходным кодом, которая обеспечивает:
Гипермедийный формат для определения мобильных приложений, называемый HXML.
Гипермедийный клиент для HXML, работающий на iOS и Android.
Точки расширения в HXML и клиенте для настройки платформы для данного приложения.
Формат
HXML был разработан так, чтобы он был знаком веб-разработчикам, привыкшим работать с HTML. Таким образом, выбор XML в качестве базового формата. Помимо привычной эргономики, XML совместим с библиотеками рендеринга на стороне сервера. Например, Jinja2 идеально подходит в качестве библиотеки шаблонов для рендеринга HXML. Знакомство с XML и простота интеграции с серверной частью упрощают его внедрение как в новые, так и в существующие базы кода. Взгляните на приложение «Hello World», написанное на HXML. Синтаксис должен быть знаком каждому, кто работал с HTML:
Но HXML — это не просто прямой порт HTML с тегами с разными именами. В предыдущих главах мы видели, как htmx расширяет HTML с помощью нескольких новых атрибутов. Эти дополнения сохраняют декларативную природу HTML, давая разработчикам возможность создавать многофункциональные веб-приложения. В HXML концепции htmx встроены в спецификацию. В частности, HXML не ограничивается взаимодействиями «щелкнуть ссылку» и «отправить форму», как базовый HTML. Он поддерживает ряд триггеров и действий для изменения содержимого на экране. Эти взаимодействия объединены в мощную концепцию «поведения». Разработчики могут даже определять новые поведенческие действия, чтобы добавить новые возможности в свое приложение без необходимости создания сценариев. Мы узнаем больше о поведении позже в этой главе.
Клиент
Hyperview предоставляет клиентскую библиотеку HXML с открытым исходным кодом, написанную на React Native. После небольшой настройки и нескольких шагов в командной строке эта библиотека компилируется в собственные двоичные файлы приложений для iOS или Android. Пользователи устанавливают приложение на свое устройство через магазин приложений. При запуске приложение отправляет HTTP-запрос к настроенному URL-адресу и отображает ответ HXML на первом экране.
Может показаться немного странным, что для разработки HDA с использованием Hyperview требуется специализированный клиентский двоичный файл. В конце концов, мы не просим пользователей сначала загрузить и установить двоичный файл для просмотра веб-приложения. Нет, пользователи просто вводят URL-адрес в адресную строку универсального веб-браузера. Один HTML-клиент отображает приложения с любого HTML-сервера.
Теоретически возможно создать эквивалентный универсальный браузер «Hyperview». Этот клиент HXML будет отображать приложения с любого сервера HXML, и пользователи будут вводить URL-адрес, чтобы указать приложение, которое они хотят использовать. Но iOS и Android построены на концепции специализированных приложений. Пользователи ожидают, что смогут найти и установить приложения из магазина приложений и запустить их с главного экрана своего устройства. Hyperview охватывает эту ориентированную на приложения парадигму современных популярных мобильных платформ. Это означает, что клиент HXML (двоичный файл приложения) отображает свой пользовательский интерфейс с одного предварительно настроенного сервера HXML:
К счастью, разработчикам не нужно писать HXML-клиент с нуля; клиентская библиотека с открытым исходным кодом выполняет 99% работы. И, как мы увидим в следующем разделе, управление клиентом и сервером в HDA дает большие преимущества.
Расширяемость
Чтобы понять преимущества архитектуры Hyperview, нам нужно сначала обсудить недостатки веб-архитектуры. В Интернете любой веб-браузер может отображать HTML с любого веб-сервера. Такой уровень совместимости возможен только при наличии четко определенных стандартов, таких как HTML5. Однако определение и развитие стандартов — трудоемкий процесс. Например, W3C потребовалось более 7 лет, чтобы пройти путь от первого проекта до рекомендации по спецификации HTML5. Это неудивительно, учитывая уровень вдумчивости, который необходим для изменения, которое затронет так много людей. Но это означает, что прогресс происходит медленно. Вам как веб-разработчику, возможно, придется годами ждать, пока браузеры не получат широкую поддержку необходимой вам функции.
Так в чем же преимущества архитектуры Hyperview? В приложении Hyperview ваше мобильное приложение отображает HXML только с вашего сервера. Вам не нужно беспокоиться о совместимости вашего сервера с другими мобильными приложениями или между вашим мобильным приложением и другими серверами. Не существует органа по стандартизации, с которым можно было бы консультироваться. Если вы хотите добавить функцию мигания в свое мобильное приложение, реализуйте элемент <blink>
в клиенте и начните возвращаться.<blink>
элементы в ответах HXML с вашего сервера. Фактически, клиентская библиотека Hyperview была создана с учетом такого типа расширяемости. Существуют точки расширения для пользовательских элементов пользовательского интерфейса и пользовательских действий поведения. Мы ожидаем и поощряем разработчиков использовать эти расширения, чтобы сделать HXML более выразительным и адаптированным к функциональности их приложений.
А благодаря расширению формата HXML и самого клиента Hyperview не нужно включать уровень сценариев в HXML. Функции, требующие логики на стороне клиента, «встраиваются» в двоичный файл клиента. Ответы HXML остаются чистыми, а пользовательский интерфейс и взаимодействия представлены в декларативном XML.
Какую архитектуру гипермедиа следует использовать?
Мы обсудили два подхода к созданию мобильных приложений с использованием гипермедиа-систем:
создайте серверную часть, которая возвращает HTML, и обслуживайте его в мобильном приложении через веб-представление.
создайте серверную часть, возвращающую HXML, и обслуживайте ее в мобильном приложении с помощью клиента Hyperview.
Я намеренно описал два подхода, чтобы подчеркнуть их сходство. Ведь они оба основаны на гипермедиа-системах, просто с разными форматами и клиентами. Оба подхода решают фундаментальные проблемы традиционной разработки мобильных приложений наподобие SPA:
Бэкэнд контролирует полное состояние приложения.
Вся логика нашего приложения собрана в одном месте.
Приложение всегда использует последнюю версию, поэтому не стоит беспокоиться об обновлении API.
Итак, какой подход следует использовать для мобильного HDA? Основываясь на нашем опыте создания приложений обоих типов, мы считаем, что подход Hyperview обеспечивает лучшее взаимодействие с пользователем. Веб-просмотр всегда будет неуместен на iOS и Android; просто не существует хорошего способа воспроизвести шаблоны навигации и взаимодействия, которые ожидают мобильные пользователи. Hyperview был создан специально для устранения ограничений подходов с толстым клиентом и веб-представлением. После первоначальных инвестиций в изучение Hyperview вы получите все преимущества архитектуры Hypermedia без недостатков, связанных с ухудшением пользовательского опыта.
Конечно, если у вас уже есть простое, удобное для мобильных устройств веб-приложение, то использование подхода веб-представления имеет смысл. Вы, безусловно, сэкономите время, поскольку вам не придется использовать свое приложение в формате HXML в дополнение к HTML. Но, как мы покажем в конце этой главы, преобразование существующего веб-приложения на основе Hypermedia в мобильное приложение Hyperview не требует больших усилий. Но прежде чем мы доберемся до этого, нам нужно представить концепции элементов и поведения в Hyperview. Затем мы перестроим наше приложение контактов в Hyperview.
Когда не следует использовать Hypermedia для создания мобильного приложения?
Гипермедиа не всегда является правильным выбором для создания мобильного приложения. Как и в Интернете, приложения, требующие высокодинамичного пользовательского интерфейса (например, приложение для работы с электронными таблицами), лучше реализовывать с помощью клиентского кода. Кроме того, некоторые приложения должны работать в автономном режиме. Поскольку для HDA требуется сервер для рендеринга пользовательского интерфейса, мобильные приложения, ориентированные на офлайн-режим, не подходят для этой архитектуры. Однако, как и в Интернете, разработчики могут использовать гибридный подход для создания своих мобильных приложений. Высокодинамичные экраны могут быть созданы с использованием сложной логики на стороне клиента, тогда как менее динамичные экраны могут быть созданы с помощью веб-представлений или Hyperview. Таким образом, разработчики могут потратить свой бюджет сложности на ядро приложения и сохранить простые экраны простыми.
Введение в HXML
Привет, мир!
HXML был разработан так, чтобы веб-разработчики чувствовали себя естественно, переходя на HTML. Давайте подробнее рассмотрим приложение «Hello World», определенное в HXML:
Корневой элемент приложения HXML.
Элемент, представляющий экран приложения
Элемент, представляющий пользовательский интерфейс экрана
Элемент, представляющий верхний заголовок экрана.
Элемент-обертка вокруг содержимого, отображаемого на экране.
Текстовое содержимое, отображаемое на экране
Здесь нет ничего странного, правда? Как и в HTML, синтаксис определяет дерево элементов с помощью начальных тегов ( <screen>
) и конечных тегов ( </screen>
). Элементы могут содержать другие элементы ( <view>
) или текст ( Hello World!
). Элементы также могут быть пустыми, представленными пустым тегом ( <styles />
). Однако вы заметите, что имена элемента HXML отличаются от имен в HTML. Давайте подробнее рассмотрим каждый из этих элементов, чтобы понять, что они делают.
<screen>
представляет пользовательский интерфейс, который отображается на одном экране мобильного приложения. Один элемент может <doc>
содержать несколько <screen>
элементов, но мы не будем сейчас вдаваться в подробности. Обычно <screen>
элемент содержит элементы, определяющие содержимое и стиль экрана.
<styles>
определяет стили пользовательского интерфейса на экране. В этой главе мы не будем вдаваться в подробности стилей в Hyperview. Достаточно сказать, что в отличие от HTML, Hyperview не использует отдельный язык (CSS) для определения стилей. Вместо этого правила стиля, такие как цвета, интервалы, макет и шрифты, определяются в HXML. На эти правила затем явно ссылаются элементы пользовательского интерфейса, подобно использованию классов в CSS.
<body>
определяет фактический пользовательский интерфейс экрана. Тело включает в себя весь текст, изображения, кнопки, формы и т. д., которые будут показаны пользователю. Это эквивалент элемента <body>
в HTML.
<header>
определяет заголовок экрана. Обычно в мобильных приложениях заголовок включает в себя некоторую навигацию (например, кнопку «Назад») и заголовок экрана. Полезно определить заголовок отдельно от остальной части тела. В некоторых мобильных ОС для заголовка будет использоваться другой переход, чем для остального содержимого экрана.
<view>
является основным строительным блоком макетов и структуры тела экрана. Думайте об этом как <div>
о HTML. Обратите внимание: в отличие от HTML, a <div>
не может содержать текст напрямую.
<text>
элементы — единственный способ отобразить текст в пользовательском интерфейсе. В этом примере «Hello World» содержится внутри <text>
элемента.
Это все, что нужно для определения базового приложения «Hello World» в HXML. Конечно, это не очень интересно. Давайте рассмотрим некоторые другие встроенные элементы дисплея.
Элементы пользовательского интерфейса
Списки
Очень распространенный шаблон в мобильных приложениях — прокрутка списка элементов. Физические свойства экрана телефона (длинный и вертикальный) и интуитивно понятный жест пролистывания большого пальца вверх и вниз делают его хорошим выбором для многих экранов.
В HXML есть специальные элементы для представления списков и элементов.
Элемент, представляющий список
Элемент, представляющий элемент в списке, с уникальным ключом
Содержимое элемента в списке.
Списки представлены двумя новыми элементами. Обертывает <list>
все элементы в списке. Его можно стилизовать как общий <view>
(ширина, высота и т. д.). Элемент <list>
содержит только <item>
элементы. Конечно, они представляют каждый уникальный элемент в списке. Обратите внимание, что атрибут <item>
должен быть key
уникальным среди всех элементов списка.
Вы можете спросить: «Зачем нам нужен собственный синтаксис для списков элементов? Разве мы не можем просто использовать кучу <view>
элементов?». Да, для списков с небольшим количеством элементов используйте вложенные<views>
будет работать вполне хорошо. Однако часто количество элементов в списке может быть достаточно длинным, чтобы требовать оптимизации для обеспечения плавного взаимодействия с прокруткой. Рассмотрите возможность просмотра ленты публикаций в приложении для социальных сетей. Когда вы продолжаете прокручивать ленту, приложение нередко показывает сотни, если не тысячи сообщений. В любой момент вы можете щелкнуть пальцем, чтобы перейти практически к любой части ленты. Мобильные устройства, как правило, имеют ограниченный объем памяти. Хранение полностью визуализированного списка элементов в памяти может потребовать больше ресурсов, чем доступно. Вот почему и iOS, и Android предоставляют API для оптимизированных пользовательских интерфейсов списков. Эти API знают, какая часть списка в данный момент отображается на экране. Чтобы сэкономить память, они удаляют невидимые элементы списка и повторно используют объекты пользовательского интерфейса элементов для экономии памяти. Используя явные <list>
и<item>
элементов в HXML, клиент Hyperview знает, как использовать эти оптимизированные API-интерфейсы списков, чтобы повысить производительность вашего приложения.
Также стоит отметить, что HXML поддерживает списки разделов. Списки разделов полезны для создания пользовательских интерфейсов на основе списков, в которых элементы списка можно группировать для удобства пользователя. Например, пользовательский интерфейс, показывающий меню ресторана, может группировать предложения по типу блюда:
Элемент, представляющий список с разделами
Первый раздел предложений закусок
Элемент заголовка раздела, отображающий текст «Закуски»
Предмет, представляющий закуску
Раздел с предложениями первых блюд
Вы заметите пару различий между <list>
и <section-list>
. Элемент списка разделов содержит только <section>
элементы, представляющие группу элементов. Раздел может содержать <section-title>
элемент. Это используется для рендеринга некоторого пользовательского интерфейса, который действует как заголовок раздела. Этот заголовок является «прикрепленным», то есть он остается на экране при прокрутке элементов, принадлежащих соответствующему разделу. Наконец, <item>
элементы действуют так же, как и в обычном списке, но могут появляться только внутри файла <section>
.
Изображений
Отображение изображений в Hyperview очень похоже на HTML, но есть несколько отличий.
Атрибут source
указывает, как загрузить изображение. Как и в HTML, источником может быть абсолютный или относительный URL-адрес. Кроме того, источником может быть URI закодированных данных, например data:image/png;base64,iVBORw
. Однако источником также может быть «локальный» URL-адрес, ссылающийся на изображение, которое включено в качестве ресурса в мобильное приложение. Локальный URL-адрес имеет префикс ./
:
Использование локальных URL-адресов — это оптимизация. Поскольку изображения находятся на мобильном устройстве, они не требуют запроса к сети и появляются быстро. Однако объединение изображения с двоичным файлом мобильного приложения увеличивает размер двоичного файла. Использование локальных изображений — хороший компромисс для изображений, к которым часто обращаются, но редко меняются. Хорошими примерами являются логотип приложения или обычные значки кнопок.
Еще одна вещь, на которую следует обратить внимание, — это наличие атрибута style
у <image>
элемента. В HXML изображения должны иметь стиль, содержащий правила для изображений width
и файлов height
. Это отличается от HTML, где <img>
элементам не нужно явно задавать ширину и высоту. веб-браузеры повторно обрабатывают содержимое веб-страницы после получения изображения и определения его размеров. Хотя перераспределение содержимого является разумным поведением для веб-документов, пользователи не ожидают, что мобильные приложения будут перераспределять содержимое при загрузке содержимого. Чтобы поддерживать статический макет, HXML требует, чтобы размеры были известны до загрузки изображения.
Входы
О входных данных в Hyperview можно рассказать очень многое. Поскольку это введение, а не исчерпывающий ресурс, я выделю лишь несколько типов материалов. Начнем с примера простейшего типа ввода — текстового поля.
Имя, используемое при сериализации данных с этого входа.
Класс стиля, примененный к элементу пользовательского интерфейса.
Текущее значение, заданное в поле
Заполнитель для отображения, когда значение пусто
Этот элемент должен быть знаком каждому, кто создавал текстовое поле в HTML. Единственное отличие состоит в том, что большинство входных данных в HTML используют <input>
элемент с type
атрибутом, например <input type="text">
. В Hyperview каждый вход имеет уникальное имя, в данном случае <text-field>
. Используя разные имена, мы можем использовать более выразительный XML для представления входных данных.
Например, давайте рассмотрим случай, когда мы хотим отобразить пользовательский интерфейс, который позволяет пользователю выбирать один из нескольких вариантов. В HTML мы бы использовали ввод переключателя, что-то вроде <input type="radio" name="choice" value="option1" />
. Каждый выбор представлен как уникальный входной элемент. Это никогда не казалось мне идеальным. В большинстве случаев переключатели группируются вместе, чтобы иметь одно и то же имя. Подход HTML приводит к большому количеству шаблонов (дублирование type="radio"
и name="choice"
для каждого выбора). Кроме того, в отличие от переключателей на настольных компьютерах, мобильные ОС не предоставляют четкого стандартного пользовательского интерфейса для выбора одного параметра. Большинство мобильных приложений используют для этих взаимодействий более богатые пользовательские интерфейсы. Итак, в HXML мы реализуем этот пользовательский интерфейс, используя элемент с именем <select-single>
:
Элемент, представляющий вход, где выбран один вариант. Имя выбора определяется здесь один раз.
Элемент, представляющий один из вариантов. Здесь определяется значение выбора.
Пользовательский интерфейс выбора. В этом примере мы используем текст, но можем использовать любые элементы пользовательского интерфейса.
Этот <select-single>
элемент является родительским для ввода для выбора одного варианта из многих. Этот элемент содержит name
атрибут, используемый при сериализации выбранного выбора. <option>
элементы внутри <select-single>
представляют доступные варианты. Обратите внимание, что каждый <option>
элемент имеет value
атрибут. При нажатии это будет выбранное значение входа. Элемент <option>
может содержать любые другие элементы пользовательского интерфейса. Это означает, что нам не мешает отображать входные данные в виде списка переключателей с метками. Мы можем отображать параметры в виде радио, тегов, изображений или чего-либо еще, что будет интуитивно понятно для нашего интерфейса. Стилизация HXML поддерживает модификаторы для нажатого и выбранного состояний, что позволяет нам настраивать пользовательский интерфейс для выделения выбранной опции.
Описание всех возможностей ввода в HXML заняло бы целую главу. Вместо этого я резюмирую несколько других элементов ввода и их особенности.
- <select-multiple>
работает как <select-single>
, но поддерживает включение и выключение нескольких опций. Это заменяет ввод флажков в HTML. – <switch>
Элемент отображает переключатель включения/выключения, который часто встречается в мобильных интерфейсах. – Элемент <date-field>
поддерживает ввод определенных дат и имеет широкий спектр настроек форматирования, диапазонов настроек и т. д.
Еще две вещи, которые следует упомянуть о входных данных. Во-первых, это <form>
элемент. Этот <form>
элемент используется для группировки входных данных для сериализации. Когда пользователь выполняет действие, которое запускает серверный запрос, клиент Hyperview сериализует все входные данные в окружении <form>
и включает их в запрос. Это справедливо для обоих запросов GET
и POST
. Мы рассмотрим это более подробно, когда будем говорить о поведении далее в этой главе. Также позже в этой главе я расскажу о поддержке пользовательских элементов в HXML. С помощью пользовательских элементов вы также можете создавать свои собственные элементы ввода. Пользовательские элементы ввода позволяют создавать невероятно мощные взаимодействия с помощью простого синтаксиса XML, который хорошо интегрируется с остальной частью HXML.
Стиль
До сих пор мы не упомянули, как применить стиль ко всем элементам HXML. В приложении Hello World мы видели, что каждый из них <screen>
может содержать <styles>
элемент. Давайте снова посетим приложение Hello World и заполним элемент <styles>
.
Элемент, инкапсулирующий все стили экрана.
Пример определения класса стиля для «body»
Применение класса стиля «body» к элементу пользовательского интерфейса
Пример применения нескольких классов стиля (h1 и info) к элементу
Вы заметите, что в HXML стиль является частью формата XML, а не использует отдельный язык, такой как CSS. Однако мы можем провести некоторые параллели между правилами CSS и элементом <style>
. Правило CSS состоит из селектора и объявлений. В текущей версии HXML единственным доступным селектором является имя класса, указанное атрибутом class
. Остальные атрибуты элемента <style>
являются объявлениями, состоящими из свойств и значений свойств.
Элементы пользовательского интерфейса внутри <screen>
могут ссылаться на <style>
правила, добавляя имена классов в их <style>
свойства. Обратите внимание на <text>
элемент вокруг «Hello World!» ссылается на два класса стилей: h1
и info
. Стили соответствующих классов объединяются в том порядке, в котором они появляются в элементе. Стоит отметить, что свойства стиля аналогичны свойствам CSS (цвет, поля/отступы, границы и т. д.). В настоящее время единственный доступный механизм компоновки основан на flexbox.
Правила стиля могут быть весьма многословными. Для краткости мы не будем включать этот <styles>
элемент в остальные примеры этой главы, если в этом нет необходимости.
Пользовательские элементы
Основные элементы пользовательского интерфейса, поставляемые с Hyperview, довольно просты. Большинству мобильных приложений требуются более богатые элементы, чтобы обеспечить удобство работы с пользователем. К счастью, HXML может легко включать в свой синтаксис пользовательские элементы. Это потому, что HXML на самом деле представляет собой просто XML, также известный как «Расширяемый язык разметки». Расширяемость уже встроена в формат! Разработчики могут свободно определять новые элементы и атрибуты для представления пользовательских элементов.
Давайте посмотрим это в действии на конкретном примере. Предположим, мы хотим добавить элемент карты в наше приложение Hello World. Мы хотим, чтобы на карте отображалась определенная область и один или несколько маркеров с определенными координатами в этой области. Переведем эти требования в XML:
Элемент
<area>
будет представлять область, отображаемую на карте. Чтобы указать область, элемент будет включать атрибуты дляlatitude
иlongitude
для центра области, а такжеlatitude-delta
иlongitude-delta
, указывающие область отображения +/- вокруг центра.Элемент
<marker>
будет представлять собой маркер в области. Координаты маркера будут определяться атрибутамиlatitude
иlongitude
атрибутами маркера.
Используя эти пользовательские элементы XML, экземпляр карты в нашем приложении может выглядеть следующим образом:
Пользовательский элемент, представляющий область, отображаемую на карте.
Пользовательский элемент, представляющий маркер, отображаемый в определенных координатах на карте.
Синтаксис чувствует себя как дома среди основных элементов HXML. Однако существует потенциальная проблема. «Область» и «маркер» — довольно общие названия. Я мог видеть <area>
элементы <marker>
, используемые в настройке для отображения диаграмм и графиков. Если наше приложение отображает и карты, и диаграммы, разметка HXML будет неоднозначной. Что должен визуализировать клиент, когда он видит <area>
или <marker>
?
Давайте определим новое пространство имен для наших элементов карты. Поскольку это пространство имен не будет пространством имен по умолчанию для документа, нам также необходимо назначить пространство имен префиксу, который мы добавим к нашим элементам:
<doc xmlns="https://hyperview.org/hyperview" xmlns:map="https://mycompany.com/hyperview-map">
Этот новый атрибут заявляет, что map:
префикс связан с пространством имен «https://mycompany.com/hyperview-map». Это пространство имен может быть любым, но помните, что цель — использовать что-то уникальное, не допускающее коллизий. Использование домена вашей компании/приложения — хороший способ гарантировать уникальность. Теперь, когда у нас есть пространство имен и префикс, нам нужно использовать его для наших элементов:
Определение пространства имен, псевдонима «map»
Добавление пространства имен в начальный тег «область»
Добавление пространства имен в самозакрывающийся тег «marker»
Добавление пространства имен в закрывающий тег «область»
Вот и все! Если бы мы представили собственную библиотеку диаграмм с элементами «площадь» и «маркер», мы бы также создали уникальное пространство имен для этих элементов. В документе HXML мы могли бы легко устранить неоднозначность <map:area>
от <chart:area>
.
На этом этапе у вас может возникнуть вопрос: «Как клиент Hyperview узнает, что нужно визуализировать карту, если мой документ включает <map:area>?» Это правда, до сих пор мы определяли только формат пользовательского элемента, но не реализовали этот элемент как функцию в нашем приложении. В следующей главе мы углубимся в детали реализации пользовательских элементов.
Поведение
Как обсуждалось в предыдущих главах, HTML поддерживает два основных типа взаимодействий:
Щелчок по гиперссылке: клиент выполнит запрос GET и отобразит ответ в виде новой веб-страницы.
Отправка формы: клиент (обычно) выполняет запрос POST с сериализованным содержимым формы и отображает ответ в виде новой веб-страницы.
Нажатия на гиперссылки и отправки форм достаточно для создания простых веб-приложений. Но использование только этих двух взаимодействий ограничивает нашу способность создавать более богатые пользовательские интерфейсы. Что, если мы хотим, чтобы что-то произошло, когда пользователь наводит указатель мыши на определенный элемент или, возможно, когда он прокручивает какой-то контент в область просмотра? Мы не можем сделать это с помощью базового HTML. Кроме того, как клики, так и отправка формы приводят к загрузке полностью новой веб-страницы. Что, если мы хотим обновить только небольшую часть текущей страницы? Это очень распространенный сценарий в многофункциональных веб-приложениях, где пользователи ожидают получения и обновления контента без перехода на новую страницу.
Таким образом, в базовом HTML взаимодействия (клики и отправки) ограничены и тесно связаны с одним действием (загрузка новой страницы). Конечно, используя JavaScript, мы можем расширить HTML и добавить новый синтаксис для поддержки желаемого взаимодействия. Htmx делает именно это с новым набором атрибутов:
Взаимодействия можно добавлять к любому элементу, а не только к ссылкам и формам.
Взаимодействие может быть инициировано щелчком мыши, отправкой, наведением мыши или любым другим событием JavaScript.
Действия, вызванные триггером, могут изменить текущую страницу, а не просто запросить новую страницу.
Разделяя элементы, триггеры и действия, htmx позволяет нам создавать многофункциональные приложения на основе Hypermedia таким образом, чтобы они были очень совместимы с синтаксисом HTML и веб-разработкой на стороне сервера.
HXML берет идею определения взаимодействий с помощью триггеров и действий и встраивает их в спецификацию. Мы называем эти взаимодействия «поведениями». <behavior>
Для их определения мы используем специальный элемент. Вот пример простого поведения, которое помещает новый экран мобильного устройства в стек навигации:
Элемент, инкапсулирующий взаимодействие с родительским
<text>
элементом.Триггер, который будет выполнять взаимодействие, в данном случае нажатие на
<text>
элемент.Действие, которое будет выполняться при срабатывании, в данном случае помещая новый экран в текущий стек.
href для загрузки на новом экране.
Давайте разберем, что происходит в этом примере. Во-первых, у нас есть <text>
элемент с содержимым «Нажми меня!». Ранее мы уже показывали <text>
элементы в примерах HXML, так что в этом нет ничего нового. Но теперь <text>
элемент содержит новый дочерний элемент <behavior>
. Этот <behavior>
элемент определяет взаимодействие с родительским <text>
элементом. Он содержит два атрибута, которые необходимы для любого поведения:
trigger
: определяет действие пользователя, которое запускает данное поведениеaction
: определяет, что происходит при срабатывании
В этом примере для параметра trigger
установлено значение press
, что означает, что это взаимодействие произойдет, когда пользователь нажмет элемент <text>
. Атрибут action
установлен на push
. push
— это действие, которое помещает новый экран в стек навигации. Наконец, Hyperview должен знать, какой контент загружать на новый экран. Здесь href
на помощь приходит атрибут. Обратите внимание, что нам не нужно определять полный URL-адрес. Как и в HTML, href
URL-адрес может быть абсолютным или относительным.
Итак, это первый пример поведения в HXML. Вы можете подумать, что этот синтаксис кажется довольно многословным. Действительно, нажатие элементов для перехода на новый экран — одно из наиболее распространенных действий в мобильном приложении. Было бы неплохо иметь более простой синтаксис для общего случая. К счастью, атрибуты trigger
и action
имеют значения по умолчанию press
и push
соответственно. Поэтому их можно опустить, чтобы очистить синтаксис:
При нажатии это поведение откроет новый экран с заданным URL-адресом.
Эта разметка <behavior>
будет производить то же взаимодействие, что и предыдущий пример. С атрибутами по умолчанию <behavior>
элемент выглядит как якорь <a>
в HTML. Но полный синтаксис достигает наших целей по разделению элементов, триггеров и действий:
Поведения можно добавить к любому элементу, они не ограничиваются ссылками и формами.
Поведения могут указывать явные действия
trigger
, а не только клики или отправку формы.Поведения могут указывать явный
action
, а не просто запрос новой страницы.Дополнительные атрибуты, например,
href
предоставляют дополнительный контекст для действия.
Кроме того, использование выделенного <behavior>
элемента означает, что один элемент может определять несколько вариантов поведения. Это позволяет нам выполнять несколько действий из одного триггера. Или мы можем выполнять разные действия для разных триггеров на одном и том же элементе. В конце этой главы мы покажем примеры силы множественного поведения. Сначала нам нужно показать разнообразие поддерживаемых действий и триггеров.
Действия
Поведенческие действия в Hyperview делятся на четыре основные категории:
Действия навигации, которые загружают новые экраны и перемещаются между ними.
Действия обновления, которые изменяют HXML текущего экрана.
Системные действия, которые взаимодействуют с возможностями уровня ОС.
Пользовательские действия, которые могут выполнять любой код, который вы добавляете в клиент.
Действия навигации
Мы уже видели простейший тип действия — push
. Мы классифицируем это push
как «действие навигации», поскольку оно связано с навигацией по экранам мобильного приложения. Добавление экрана в стек навигации — это лишь одно из нескольких действий навигации, поддерживаемых в Hyperview. Пользователи также должны иметь возможность возвращаться к предыдущим экранам, открывать и закрывать модальные окна, переключаться между вкладками или переходить на произвольные экраны. Каждый из этих типов навигации поддерживается разными значениями атрибута action
:
push
: добавить новый экран в текущий стек навигации. Это выглядит как экран, выдвигающийся справа поверх текущего экрана.new
: открыть новый стек навигации в модальном режиме. Это выглядит как экран, выдвигающийся снизу вверх по текущему экрану.back
: Это дополнение кpush
действию. Он выталкивает текущий экран из стека навигации (сдвигая его вправо).close
: Это дополнение кnew
действию. Он закрывает текущий стек навигации (сдвигая его вниз).reload
: аналогично кнопке «Обновить» в браузере, она повторно запросит содержимое текущего экрана.navigate
: Это действие попытается найти экран с данным изображением,href
уже загруженным в приложение. Если экран существует, приложение перейдет на него. Если он не существует, он будет действовать так же, какpush
.
push
, new
, и navigate
все загружают новый экран. Таким образом, им требуется href
атрибут, чтобы Hyperview знал, какой контент запрашивать для нового экрана. back
и close
не загружайте новые экраны и, следовательно, не требуйте href
атрибута. reload
это интересный случай. По умолчанию он будет использовать URL-адрес экрана при повторном запросе содержимого экрана. Однако если вы хотите заменить экран другим, вы можете указать атрибут href
в reload
элементе поведения.
Давайте посмотрим на пример приложения «виджеты», которое использует несколько действий навигации на одном экране:
Переводит пользователя на предыдущий экран
Открывает новое модальное окно для добавления виджета.
Перезагружает содержимое экрана, показывая новые виджеты из серверной части.
Открывает новый экран с подробной информацией о конкретном виджете.
Большинству экранов вашего приложения потребуется возможность возврата пользователя к предыдущему экрану. Обычно это делается с помощью кнопки в заголовке, которая использует действие «назад» или «закрыть», в зависимости от того, как был открыт экран. В этом примере мы предполагаем, что экран виджетов был помещен в стек навигации, поэтому действие «назад» является подходящим. Заголовок содержит вторую кнопку, которая позволяет пользователю ввести данные для нового виджета. Нажатие этой кнопки откроет модальное окно с экраном «Новый виджет». Поскольку этот экран «Новый виджет» откроется как модальный, ему потребуется соответствующее действие «закрыть», чтобы закрыться и снова отобразить наш экран «виджетов». Наконец, чтобы просмотреть более подробную информацию о конкретном виджете, каждый<item>
элемент содержит поведение с действием «push». Это действие переместит экран «Сведения о виджете» в текущий стек навигации. Как и на экране «Виджеты», для «Сведения о виджете» в заголовке потребуется кнопка, которая использует действие «назад», чтобы позволить пользователю вернуться назад.
В Интернете браузер выполняет основные задачи навигации, такие как переход назад/вперед, перезагрузка текущей страницы или переход к закладке. iOS и Android не предоставляют такую универсальную навигацию для собственных мобильных приложений. Разработчики приложений должны решить эту проблему самостоятельно. Действия навигации в HXML предоставляют разработчикам простой, но мощный способ создания архитектуры, подходящей для их приложения.
Обновить действия
Поведенческие действия не ограничиваются только навигацией между экранами. Их также можно использовать для изменения содержимого текущего экрана. Мы называем это «действиями обновления». Подобно действиям навигации, действия обновления отправляют запрос на серверную часть. Однако ответ представляет собой не весь документ HXML, а его фрагмент. Этот фрагмент добавляется в HXML текущего экрана, что приводит к обновлению пользовательского интерфейса. Атрибут action
определяет <behavior>
, как фрагмент включается в HXML. Нам также необходимо ввести новый target
атрибут, <behavior>
чтобы определить, где фрагмент будет включен в существующий документ. Атрибут target
представляет собой ссылку на идентификатор существующего элемента на экране.
Hyperview в настоящее время поддерживает следующие действия обновления, представляющие различные способы включения фрагмента в экран:
replace
: заменяет весь целевой элемент фрагментомreplace-inner
: заменяет дочерние элементы целевого элемента фрагментомappend
: добавляет фрагмент после последнего дочернего элемента целевого элемента.prepend
: добавляет фрагмент перед первым дочерним элементом целевого элемента.
Давайте рассмотрим несколько примеров, чтобы сделать это более конкретным. В этих примерах предположим, что наш бэкэнд принимает GET
запросы к /fragment
, а ответом является фрагмент HXML, который выглядит как <text>My fragment</text>
.
Заменяет элемент area1 полученным фрагментом.
Заменяет дочерние элементы области2 выбранным фрагментом.
Добавляет полученный фрагмент в область 3.
Добавляет извлеченный фрагмент в область 4.
В этом примере у нас есть экран с четырьмя кнопками, соответствующими четырем действиям обновления: replace
, replace-inner
, append
, prepend
. Под каждой кнопкой есть соответствующая, <view>
содержащая текст. Обратите внимание, что поведение id
каждого представления соответствует target
поведению соответствующей кнопки.
Когда пользователь нажимает первую кнопку, клиент Hyperview отправляет запрос на /fragment
. Далее он ищет цель, то есть элемент с идентификатором «area1». Наконец, он заменяет <view id="area1">
элемент извлеченным фрагментом <text>My fragment</text>
. Существующее представление и текст, содержащийся в этом представлении, будут заменены. Для пользователя это будет выглядеть так, будто «Существующий контент» был изменен на «Мой фрагмент». В HXML этот элемент <view id="area1">
также исчезнет.
Вторая кнопка ведет себя аналогично первой. Однако replace-inner
действие не удаляет целевой элемент с экрана, а только заменяет дочерние элементы. Это означает, что результирующая разметка будет выглядеть так <view id="area2"><text>My fragment</text></view>
.
Третья и четвертая кнопки не удаляют контент с экрана. Вместо этого фрагмент будет добавлен либо после (в случае append
), либо перед ( prepend
) дочерними элементами целевого элемента.
Для полноты картины давайте посмотрим на состояние экрана после того, как пользователь нажмет все четыре кнопки:
Фрагмент полностью заменил цель с помощью
replace
действия.Фрагмент заменил дочерних элементов цели с помощью
replace-inner
действия.Фрагмент добавлен как последний дочерний элемент цели с помощью
append
действияфрагмент добавлен как первый дочерний элемент цели с помощью
prepend
действия
В приведенных выше примерах показаны действия, отправляющие GET
запросы к бэкэнду. Но эти действия также могут делать POST
запросы, устанавливая verb="post"
на <behavior>
элемент. Для обоих запросов GET
и POST
данные родительского <form>
элемента будут сериализованы и включены в запрос. Для GET
запросов содержимое будет закодировано в URL-адресе и добавлено в качестве параметров запроса. Для POST
запросов содержимое будет закодировано в виде URL-адреса и установлено в теле запроса. Поскольку они поддерживают POST
и формируют данные, действия обновления часто используются для отправки данных на серверную часть.
Пока что наш пример действий по обновлению требует получения нового контента из серверной части и добавления его на экран. Но иногда нам просто хочется изменить состояние существующих элементов. Наиболее распространенное состояние элемента, которое необходимо изменить, — это его видимость. В Hyperview есть hide
, show
и toggle
действия, которые делают именно это. Как и другие действия обновления, hide
, show
и toggle
используйте target
атрибут, чтобы применить действие к элементу на текущем экране.
Скрывает элемент с идентификатором «area».
Показывает элемент с идентификатором «area».
Переключает видимость элемента с идентификатором «area».
Элемент, на который направлены действия.
В этом примере три кнопки с надписью «Скрыть», «Показать» и «Переключить» изменят состояние отображения <view>
«области» с идентификатором. Нажатие «Скрыть» несколько раз не окажет никакого влияния, если представление будет скрыто. Аналогично, нажатие кнопки «Показать» несколько раз не повлияет на отображение представления. Нажатие «Переключить» будет продолжать переключать статус видимости элемента между отображением и скрытием.
Hyperview включает в себя и другие действия, которые изменяют существующий HXML. Мы не будем рассматривать их подробно, но я кратко упомяну их здесь:
set-value
: это действие может установить значение элемента ввода, такого как<text-field>
,<switch>
,<select-single>
и т. д.select-all
иunselect-all
работайте с<select-multiple>
элементом, чтобы выбрать или отменить выбор всех параметров.
Системные действия
Некоторые стандартные действия Hyperview вообще не взаимодействуют с HXML. Вместо этого они предоставляют функциональные возможности, предоставляемые мобильной ОС. Например, и Android, и iOS поддерживают пользовательский интерфейс «Поделиться» на системном уровне. Этот пользовательский интерфейс позволяет обмениваться URL-адресами и сообщениями из одного приложения в другое. В Hyperview есть share
действие для поддержки этого взаимодействия. Он включает в себя собственное пространство имен и атрибуты, специфичные для общего ресурса.
Определяет пространство имен для действия общего доступа.
Действие этого поведения приведет к появлению общего листа.
URL-адрес для совместного использования.
Сообщение, которым нужно поделиться.
Мы видели пространства имен XML, когда говорили о пользовательских элементах. Здесь мы используем пространство имен для атрибутов url
и message
в файле <behavior>
. Эти имена атрибутов являются общими и, вероятно, используются другими компонентами и поведениями, поэтому пространство имен гарантирует отсутствие двусмысленности. При нажатии срабатывает действие «поделиться». Значения атрибутов url
и message
будут переданы в системный общий пользовательский интерфейс. Оттуда пользователь сможет поделиться URL-адресом и сообщением через SMS, электронную почту или другие коммуникационные приложения.
Действие share
показывает, как действие поведения может использовать пользовательские атрибуты для передачи дополнительных данных, необходимых для взаимодействия. Но некоторые действия требуют еще более структурированных данных. Это можно обеспечить через дочерние элементы в файле <behavior>
. Hyperview использует это для реализации alert
действия. Действие alert
отображает настроенное диалоговое окно системного уровня. Это диалоговое окно требует настройки заголовка и сообщения, а также настраиваемых кнопок. Каждая кнопка должна затем вызывать другое поведение при нажатии. Этот уровень конфигурации невозможно реализовать только с помощью атрибутов, поэтому мы используем специальные дочерние элементы для представления поведения каждой кнопки.
Определяет пространство имен для действия предупреждения.
Действие этого поведения приведет к появлению системного диалогового окна.
Название диалогового окна.
Содержимое диалогового окна.
Опция «Продолжить» в диалоговом окне
При нажатии «продолжить» в стек навигации добавляется новый экран.
Опция «Отмена», которая закрывает диалоговое окно.
Как и share
поведение, alert
использует пространство имен для определения некоторых атрибутов и элементов. Сам элемент <behavior>
содержит атрибуты title
и message
для диалогового окна. Параметры кнопки диалогового окна определяются с использованием нового <option>
элемента, вложенного в файл <behavior>
. Обратите внимание, что каждый <option>
элемент имеет метку, а затем, при необходимости, содержит самого <behavior>
себя! Такая структура HXML позволяет системному диалогу инициировать любое взаимодействие, которое можно определить как<behavior>
. В приведенном выше примере нажатие кнопки «Продолжить» откроет новый экран. Но мы могли бы с тем же успехом вызвать действие обновления, чтобы изменить текущий экран. Мы могли бы даже открыть общий лист или второе диалоговое окно. Но, пожалуйста, не делайте этого в реальном приложении! С большой властью приходит большая ответственность.
Пользовательские действия
Вы можете создать множество мобильных пользовательских интерфейсов с помощью стандартной навигации, обновления и системных действий Hyperview. Но стандартный набор может не охватывать все взаимодействия, необходимые для вашего мобильного приложения. К счастью, система действий расширяема. Точно так же, как вы можете добавлять в Hyperview собственные элементы, вы также можете добавлять настраиваемые действия по поведению. Пользовательские действия имеют синтаксис, аналогичный действиям share
и alert
, используя пространства имен для атрибутов, передающих дополнительные данные. Пользовательские действия также имеют полный доступ к HXML текущего экрана, поэтому они могут изменять состояние или добавлять/удалять элементы с текущего экрана. В следующей главе мы создадим настраиваемое поведенческое действие для улучшения нашего приложения для мобильных контактов.
Триггеры
Мы уже видели простейший тип триггера — press
на элементе. Hyperview поддерживает множество других распространенных триггеров, используемых в мобильных приложениях.
Длительное нажатие
С прессой тесно связано длительное нажатие. Поведение with trigger="longPress"
сработает, когда пользователь нажмет и удержит элемент. Взаимодействия «длительного нажатия» часто используются для ярлыков и дополнительных функций. Иногда элементы поддерживают разные действия как для a, так press
и для longPress
. Это делается с использованием нескольких <behavior>
элементов в одном элементе пользовательского интерфейса.
Обычное нажатие откроет следующий экран.
Длительное нажатие откроет другой экран.
В этом примере обычное нажатие откроет новый экран и запросит контент из /next-screen
. Однако долгое нажатие откроет новый экран с содержимым из /secret-screen
. Это надуманный пример для краткости. Лучшим UX было бы, чтобы при длительном нажатии вызывалось контекстное меню с ярлыками и дополнительными параметрами. Этого можно добиться, action="alert"
открыв системное диалоговое окно с помощью ярлыков.
Нагрузка
Иногда нам нужно, чтобы действие запускалось сразу после загрузки экрана. trigger="load"
делает именно это. Один из вариантов использования — быстро загрузить оболочку экрана, а затем заполнить основной контент на экране вторым действием обновления.
Элемент-контейнер без фактического содержимого
Поведение, которое немедленно запускает запрос /content на замену контейнера.
Загрузка пользовательского интерфейса, который появляется до тех пор, пока содержимое не будет извлечено и заменено.
В этом примере мы загружаем экран с заголовком («Мое приложение»), но без контента. Вместо этого мы показываем <view>
«контейнер» с идентификатором и текст «Загрузка…». Как только этот экран загружается, поведение trigger=“load”
запускает replace
действие. Он запрашивает содержимое по /content
пути и заменяет представление контейнера ответом.
Видимый
В отличие от load
, visible
триггер будет выполнять поведение только тогда, когда элемент с этим поведением прокручивается в область просмотра на мобильном устройстве. Это visible
действие обычно используется для реализации взаимодействия с бесконечной прокруткой нескольких <list>
элементов <item>
. Последний элемент в списке включает поведение с trigger="visible"
. Действие append
выберет следующую страницу элементов и добавит их в список.
Обновить
Этот триггер фиксирует действие «потянуть, чтобы обновить» для элементов <list>
и <view>
элементов. Это взаимодействие связано с получением актуального контента из серверной части. Таким образом, оно обычно сочетается с действием обновления или перезагрузки для отображения последних данных на экране.
Когда представление опустится для обновления, перезагрузите экран.
Обратите внимание, что добавление поведения с trigger="refresh"
к элементу <view>
или <list>
добавит к элементу взаимодействие «вытягивание для обновления», включая отображение счетчика при перемещении элемента вниз.
Фокусировка, размытие и изменение
Эти триггеры связаны с взаимодействием с элементами ввода. Таким образом, они будут запускать только поведение, связанное с такими элементами, как <text-field>
. focus
и blur
сработает, когда пользователь фокусирует и размывает элемент ввода соответственно. change
сработает при изменении значения элемента ввода, например, когда пользователь вводит букву в текстовое поле. Эти триггеры часто используются с поведениями, которые требуют выполнения некоторой проверки полей формы на стороне сервера. Например, когда пользователь вводит имя пользователя, а затем размывает поле, может сработать поведение, требующее blur
выполнения запроса к серверной части и проверки уникальности имени пользователя. Если введенное имя пользователя не уникально, ответ может включать сообщение об ошибке, сообщающее пользователю, что ему нужно выбрать другое имя пользователя.
Использование нескольких вариантов поведения
Большинство приведенных выше примеров присоединяют одиночный элемент <behavior>
к элементу. Но в Hyperview такого ограничения нет; элементы могут определять несколько вариантов поведения. Мы уже видели пример, когда для одного элемента запускались разные действия press
и longPress
. Но мы также можем запускать несколько действий по одному и тому же триггеру.
В этом, по общему признанию, надуманном примере мы хотим скрыть два элемента на экране при нажатии кнопки «Скрыть». Эти два элемента в HXML находятся далеко друг от друга, и их нельзя скрыть, скрыв общий родительский элемент. Но мы можем одновременно активировать два поведения, каждое из которых выполняет действие «скрыть», но нацелено на разные элементы.
Скрыть элемент с идентификатором «area1» при нажатии.
Скрыть элемент с идентификатором «area2» при нажатии.
Hyperview обрабатывает поведение в том порядке, в котором оно появляется в разметке. В этом случае сначала будет скрыт элемент с идентификатором «area1», а затем элемент с идентификатором «area2». Поскольку «скрыть» — это мгновенное действие (т. е. оно не отправляет HTTP-запрос), оба элемента будут выглядеть спрятанными одновременно. Но что, если мы запустим два действия, которые зависят от ответов HTTP-запросов (например, «replace-inner»)? В этом случае каждое отдельное действие обрабатывается, как только Hyperview получает ответ HTTP. В зависимости от задержки в сети эти два действия могут вступить в силу в любом порядке, и их одновременное применение не гарантируется.
Мы видели элементы с различным поведением и разными триггерами. И мы видели элементы с несколькими вариантами поведения с одним и тем же триггером. Эти понятия также можно смешивать. В рабочем приложении Hyperview нет ничего необычного в том, что он содержит несколько вариантов поведения, некоторые из которых срабатывают одновременно, а другие — при разных взаимодействиях. Использование нескольких вариантов поведения с настраиваемыми действиями сохраняет декларативность HXML без ущерба для функциональности.
Краткое содержание
Во-первых, HXML выглядит и ощущается как HTML. Веб-разработчики, знакомые со средами рендеринга на стороне сервера, могут использовать те же методы для написания HXML. В дополнение к базовым элементам пользовательского интерфейса ( <view>
, <text>
, <image>
) HXML определяет элементы для реализации пользовательского интерфейса, специфичного для мобильных устройств. Сюда входят шаблоны макета ( <screen>
, <list>
, <section-list>
) и элементы ввода ( <switch>
, <select-single>
, <select-multiple>
).
Во-вторых, взаимодействия в HXML определяются с помощью поведения. Вдохновленные htmx, <behavior>
элементы отделяют взаимодействие пользователя (триггеры) от результирующих действий. Существует три широкие категории поведенческих действий:
Действия навигации (
push
,back
) позволяют перемещаться между экранами мобильного приложения.Действия обновления (
replace
,append
) позволяют обновить экран новыми фрагментами HXML, запрошенными с сервера.Системные действия (
alert
,share
) позволяют взаимодействовать с функциями системного уровня на iOS и Android.
Наконец, сам HXML был разработан для настройки. Разработчики могут определять настраиваемые элементы и настраиваемые поведенческие действия, чтобы расширить возможности взаимодействия пользователей со своими приложениями.
Гипермедиа для мобильных устройств
Существует веский аргумент в пользу приложений, управляемых гипермедиа, на мобильных устройствах. Платформы мобильных приложений подталкивают разработчиков к архитектуре толстого клиента. Но приложения, использующие толстый клиент, страдают от тех же проблем, что и SPA в Интернете. Использование архитектуры гипермедиа для мобильных приложений может решить эти проблемы.
Hyperview, основанный на новом формате под названием HXML, предлагает путь сюда. Он предоставляет мобильный тонкий клиент с открытым исходным кодом для рендеринга HXML. А HXML открывает набор элементов и шаблонов, соответствующих мобильным пользовательским интерфейсам. Разработчики могут развивать Hyperview в соответствии с требованиями своих приложений, полностью используя архитектуру гипермедиа. Это победа.
Да, гипермедиа может работать и для мобильных приложений. В следующих двух главах мы покажем, как превратить веб-приложение Contact.app в собственное мобильное приложение с помощью Hyperview.
Заметки о Hypermedia: максимизируйте сильные стороны сервера
Поскольку мы не используем HTML, в разделах книги, посвященных Hyperview, мы собираемся сделать более широкие наблюдения по гипермедиа, а не предлагать советы и мысли, специфичные для HTML.
Большим преимуществом подхода, основанного на гипермедиа, является то, что он делает серверную среду гораздо более важной при создании вашего веб-приложения. Вместо того, чтобы просто создавать JSON, ваша серверная часть является неотъемлемым компонентом пользовательского опыта вашего гипермедийного приложения.
В связи с этим имеет смысл внимательно изучить доступный там функционал. Например, многие старые веб-фреймворки обладают невероятно глубокими функциями создания HTML. Такие функции, как кэширование на стороне сервера, могут сыграть решающую роль между невероятно быстрым веб-приложением и медленным взаимодействием с пользователем.
Найдите время, чтобы изучить все доступные вам инструменты.
Хорошее практическое правило — стремиться к тому, чтобы ответы сервера в вашем приложении, управляемом гипермедиа, занимали менее 100 мс, и в зрелых серверных платформах есть инструменты, которые помогут это сделать.
Серверные среды часто имеют чрезвычайно зрелые механизмы для правильной факторизации (или организации) вашего кода. Шаблон «Модель/Представление/Контроллер» хорошо развит в большинстве сред, а такие инструменты, как модули, пакеты и т. д., обеспечивают отличный способ организации вашего кода.
В то время как современные SPA и мобильные пользовательские интерфейсы обычно организуются с помощью компонентов, приложения, управляемые гипермедиа, обычно организуются посредством включения шаблонов, где шаблоны на стороне сервера разбиваются в соответствии с потребностями приложения в рендеринге гипермедиа, а затем включаются друг в друга. по мере необходимости. Это, как правило, приводит к меньшему количеству и более объемным файлам, чем в компонентном приложении.
Еще одна технология, на которую следует обратить внимание, — это фрагменты шаблона, которые позволяют визуализировать только часть файла шаблона. Это может еще больше сократить количество файлов шаблонов, необходимых для вашего серверного приложения.
Похожий совет — воспользоваться прямым доступом к хранилищу данных. Когда приложение создается с использованием подхода «толстого клиента», хранилище данных обычно находится за API данных (например, JSON). Этот уровень косвенности часто не позволяет разработчикам внешнего интерфейса в полной мере использовать инструменты, доступные в хранилище данных. GraphQL, например, может помочь решить эту проблему, но имеет проблемы, связанные с безопасностью, которые, похоже, не совсем понятны многим разработчикам.
С другой стороны, когда вы создаете гипермедиа на стороне сервера, разработчик, создающий эту гипермедиа, может иметь полный доступ к хранилищу данных и использовать преимущества, например, функций объединения и агрегации в хранилищах SQL.
Это дает гораздо больше выразительных возможностей непосредственно в руки разработчика, создающего окончательную гипермедиа. Поскольку ваш гипермедийный API может быть структурирован в соответствии с вашими потребностями пользовательского интерфейса, вы можете настроить каждую конечную точку так, чтобы она выдавала как можно меньше запросов к хранилищу данных.
Хорошее эмпирическое правило заключается в том, что каждый запрос к вашему серверу должен иметь три или меньше обращений к хранилищу данных. Если вы будете следовать этому эмпирическому правилу, ваше приложение, управляемое гипермедиа, должно работать очень быстро.
Last updated