Объединение веб-приложений и нативных приложений с помощью четырех неизвестных API JavaScript
Пару лет назад четыре API JavaScript оказались в самом низу осведомленности в опросе «Состояние JavaScript». Я заинтересовался этими API, потому что у них огромный потенциал быть полезными, но они не получили того признания, которого они заслуживают. Даже после быстрого поиска я был поражен тем, сколько новых веб-API было добавлено в спецификацию ECMAScript, которые не получают должного внимания и имеют недостаточную осведомленность и поддержку браузеров.
Большинство этих API предназначены для поддержки прогрессивных веб-приложений (PWA) и сокращения разрыва между веб-приложениями и собственными приложениями. Имейте в виду, что создание PWA предполагает нечто большее, чем просто добавление файла манифеста. Конечно, по определению это PWA, но на практике он функционирует как закладка на главном экране. На самом деле нам нужно несколько API, чтобы обеспечить полностью нативный интерфейс приложения в Интернете. И четыре API, на которые я хотел бы пролить свет, являются частью той головоломки PWA, которая привносит в Интернет то, что, как мы когда-то считали, возможно только в нативных приложениях.
Вы можете увидеть все эти API в действии в этой демонстрации по мере продвижения.
1. API ориентации экрана
API ориентации экрана можно использовать для определения текущей ориентации устройства. Как только мы узнаем, просматривает ли пользователь книжную или альбомную ориентацию, мы можем использовать это для улучшения пользовательского интерфейса для мобильных устройств, соответствующим образом изменив пользовательский интерфейс. Мы также можем использовать его для блокировки экрана в определенном положении, что полезно для отображения видео и других полноэкранных элементов, которым выгодно более широкое окно просмотра.
Используя объект глобального экрана, вы можете получить доступ к различным свойствам, которые экран использует для визуализации страницы, включая объект screen.orientation. Он имеет два свойства:
- type: текущая ориентация экрана. Это может быть: «
portrait-primary
», «portrait-secondary
», «landscape-primary
» или «landscape-secondary
».
- angle: текущий угол ориентации экрана. Это может быть любое число от 0 до 360 градусов, но обычно оно кратно 90 градусам (например,
0
,90
,180
или270
).
На мобильных устройствах, если угол равен 0 градусов, тип чаще всего оценивается как «портретный» (вертикальный), но на настольных устройствах это обычно «альбомный» (горизонтальный). Это делает свойство type
точным для определения истинного положения устройства.
Объект screen.orientation также имеет два метода:
.lock()
: это асинхронный метод, который принимает значениеtype
в качестве аргумента для блокировки экрана.
.unlock()
: этот метод разблокирует экран до ориентации по умолчанию.
И, наконец, screen.orientation
учитывает событие orientationchange
, чтобы узнать, когда ориентация изменилась.
ПОДДЕРЖКА БРАУЗЕРА
ПОИСК И БЛОКИРОВКА ОРИЕНТАЦИИ ЭКРАНА
Давайте напишем короткую демонстрацию с использованием API ориентации экрана, чтобы узнать ориентацию устройства и зафиксировать его в текущем положении.
Это может быть наш шаблон HTML:
<main>
<p>
Orientation Type: <span class="orientation-type"></span>
<br />
Orientation Angle: <span class="orientation-angle"></span>
</p>
<button type="button" class="lock-button">Lock Screen</button>
<button type="button" class="unlock-button">Unlock Screen</button>
<button type="button" class="fullscreen-button">Go Full Screen</button>
</main>
На стороне JavaScript мы вставляем тип ориентации экрана и свойства угла в наш HTML.
let currentOrientationType = document.querySelector(".orientation-type");
let currentOrientationAngle = document.querySelector(".orientation-angle");
currentOrientationType.textContent = screen.orientation.type;
currentOrientationAngle.textContent = screen.orientation.angle;
Теперь мы можем увидеть свойства ориентации и угла устройства. На моем ноутбуке они «landscape-primary
» и 0°
.
Если мы прослушаем событие изменения ориентации окна, мы увидим, как значения обновляются каждый раз, когда экран вращается.
window.addEventListener("orientationchange", () => {
currentOrientationType.textContent = screen.orientation.type;
currentOrientationAngle.textContent = screen.orientation.angle;
});
Чтобы заблокировать экран, нам нужно сначала перейти в полноэкранный режим, поэтому мы воспользуемся еще одной чрезвычайно полезной функцией: Fullscreen API. Никто не хочет, чтобы веб-страница переходила в полноэкранный режим без его согласия, поэтому для работы нам нужна временная активация (т. е. щелчок пользователя) элемента DOM.
У полноэкранного API есть два метода:
Document.exitFullscreen()
используется из глобального объекта документа,
Element.requestFullscreen()
переводит указанный элемент и его потомков в полноэкранный режим.
Мы хотим, чтобы вся страница была полноэкранной, чтобы мы могли вызвать метод из корневого элемента объекта document.documentElement
:
const fullscreenButton = document.querySelector(".fullscreen-button");
fullscreenButton.addEventListener("click", async () => {
// If it is already in full-screen, exit to normal view
if (document.fullscreenElement) {
await document.exitFullscreen();
} else {
await document.documentElement.requestFullscreen();
}
});
Далее мы можем заблокировать экран в его текущей ориентации:
const lockButton = document.querySelector(".lock-button");
lockButton.addEventListener("click", async () => {
try {
await screen.orientation.lock(screen.orientation.type);
} catch (error) {
console.error(error);
}
});
И делаем обратное с кнопкой разблокировки:
const unlockButton = document.querySelector(".unlock-button");
unlockButton.addEventListener("click", () => {
screen.orientation.unlock();
});
НЕ МОЖЕМ ПРОВЕРИТЬ ОРИЕНТАЦИЮ МЕДИА-ЗАПРОСОМ?
Да! Мы действительно можем проверить ориентацию страницы с помощью функции ориентации мультимедиа в медиазапросе CSS. Однако медиа-запросы вычисляют текущую ориентацию, проверяя, является ли ширина «больше высоты» для альбомной ориентации или «меньше» для книжной ориентации. Напротив,
Возможно, вы заметили, как PWA, такие как Instagram и X, переводят экран в портретный режим, даже если исходная ориентация системы разблокирована. Важно отметить, что такое поведение достигается не с помощью API ориентации экрана, а путем установки свойства ориентации в файле manifest.json
на желаемый тип ориентации.
2. API ориентации устройства
Еще один API, на который я хотел бы обратить внимание, — это API ориентации устройств. Он обеспечивает доступ к датчикам гироскопа устройства для считывания ориентации устройства в пространстве; что-то постоянно используемое в мобильных приложениях, в основном в играх. API делает это возможным с помощью события ориентации устройства, которое срабатывает каждый раз, когда устройство перемещается. Он имеет следующие свойства:
event.alpha
: Ориентация по осиZ
в диапазоне от0
до360
градусов.
event.beta
: Ориентация по осиX
в диапазоне от-180
до180
градусов.
event.gamma
: Ориентация по осиY
в диапазоне от-90
до90
градусов.
ПОДДЕРЖКА БРАУЗЕРА
ПЕРЕМЕЩЕНИЕ ЭЛЕМЕНТОВ С ПОМОЩЬЮ ВАШЕГО УСТРОЙСТВА
В данном случае мы создадим 3D-куб с помощью CSS, который можно будет вращать с помощью вашего устройства! Полные инструкции, которые я использовал для создания исходного CSS-куба, принадлежат Дэвиду ДеСандро, и их можно найти в его введении в 3D-преобразования.
Вы можете увидеть необработанный полный HTML-код в демо-версии, но давайте распечатаем его здесь для потомков:
<main>
<div class="scene">
<div class="cube">
<div class="cube__face cube__face--front">1</div>
<div class="cube__face cube__face--back">2</div>
<div class="cube__face cube__face--right">3</div>
<div class="cube__face cube__face--left">4</div>
<div class="cube__face cube__face--top">5</div>
<div class="cube__face cube__face--bottom">6</div>
</div>
</div>
<h1>Device Orientation API</h1>
<p>
Alpha: <span class="currentAlpha"></span>
<br />
Beta: <span class="currentBeta"></span>
<br />
Gamma: <span class="currentGamma"></span>
</p>
</main>
Чтобы быть кратким, я не буду здесь объяснять код CSS. Просто имейте в виду, что он предоставляет необходимые стили для 3D-куба и его можно вращать по всем осям с помощью функции CSS Rotate()
.
Теперь с помощью JavaScript мы слушаем событие ориентации устройства окна и получаем доступ к данным ориентации события:
const currentAlpha = document.querySelector(".currentAlpha");
const currentBeta = document.querySelector(".currentBeta");
const currentGamma = document.querySelector(".currentGamma");
window.addEventListener("deviceorientation", (event) => {
currentAlpha.textContent = event.alpha;
currentBeta.textContent = event.beta;
currentGamma.textContent = event.gamma;
});
Чтобы увидеть, как изменяются данные на настольном устройстве, мы можем открыть DevTools Chrome и получить доступ к панели датчиков для эмуляции вращающегося устройства.
Чтобы повернуть куб, мы изменяем его свойства преобразования CSS в соответствии с данными ориентации устройства:
const currentAlpha = document.querySelector(".currentAlpha");
const currentBeta = document.querySelector(".currentBeta");
const currentGamma = document.querySelector(".currentGamma");
const cube = document.querySelector(".cube");
window.addEventListener("deviceorientation", (event) => {
currentAlpha.textContent = event.alpha;
currentBeta.textContent = event.beta;
currentGamma.textContent = event.gamma;
cube.style.transform = `rotateX(${event.beta}deg) rotateY(${event.gamma}deg) rotateZ(${event.alpha}deg)`;
});
Вот результат:
3. API вибрации
Давайте обратим внимание на Vibration API, который, что неудивительно, обеспечивает доступ к механизму вибрации устройства. Это удобно, когда нам нужно оповещать пользователей уведомлениями в приложении, например, когда процесс завершен или получено сообщение. Тем не менее, мы должны использовать его экономно; никто не хочет, чтобы его телефон разрывался от уведомлений.
API вибрации предоставляет нам только один метод, и это все, что нам нужно: navigator.vibrate()
.
vibrate()
доступен глобально из объекта навигатора и принимает аргумент продолжительности вибрации в миллисекундах. Это может быть как число, так и массив чисел, представляющий покровителя вибраций и пауз.
navigator.vibrate(200); // vibrate 200ms
navigator.vibrate([200, 100, 200]); // vibrate 200ms, wait 100, and vibrate 200ms.
БРАУЗЕРНАЯ ПОДДЕРЖКА
ДЕМО API ВИБРАЦИИ
Давайте сделаем быструю демонстрацию, в которой пользователь вводит количество миллисекунд, в течение которых его устройство должно вибрировать, и нажимает кнопки для запуска и остановки вибрации, начиная с разметки:
<main>
<form>
<label for="milliseconds-input">Milliseconds:</label>
<input type="number" id="milliseconds-input" value="0" />
</form>
<button class="vibrate-button">Vibrate</button>
<button class="stop-vibrate-button">Stop</button>
</main>
Добавим прослушиватель событий клика и вызовем метод vibrate()
:
const vibrateButton = document.querySelector(".vibrate-button");
const millisecondsInput = document.querySelector("#milliseconds-input");
vibrateButton.addEventListener("click", () => {
navigator.vibrate(millisecondsInput.value);
});
Чтобы прекратить вибрацию, мы заменяем текущую вибрацию вибрацией с нулевой миллисекундой.
const stopVibrateButton = document.querySelector(".stop-vibrate-button");
stopVibrateButton.addEventListener("click", () => {
navigator.vibrate(0);
});
4. API выбора контактов
Раньше к «контактам» устройства могли подключаться только собственные приложения. Но теперь у нас есть четвертый и последний API, на который я хочу обратить внимание: API выбора контактов.
API предоставляет веб-приложениям доступ к спискам контактов устройства. В частности, мы получаем асинхронный метод Contacts.select()
, доступный через объект навигатора, который принимает следующие два аргумента:
- Свойства: это массив, содержащий информацию, которую мы хотим получить из карточки контакта, например, «имя», «адрес», «электронная почта», «телефон» и «значок».
- Параметры: это объект, который может содержать только логическое свойство Multiple, определяющее, может ли пользователь выбирать один или несколько контактов одновременно.
ПОДДЕРЖКА БРАУЗЕРА
Боюсь, что на момент написания этой статьи поддержка браузеров практически отсутствует, ограничиваясь Chrome Android, Samsung Internet и собственным веб-браузером Android.
ВЫБОР КОНТАКТОВ ПОЛЬЗОВАТЕЛЯ
Мы сделаем еще одно демо для выбора и отображения контактов пользователя на странице. Опять же, начиная с HTML:
<main>
<button class="get-contacts">Get Contacts</button>
<p>Contacts:</p>
<ul class="contact-list">
<!-- We’ll inject a list of contacts -->
</ul>
</main>
Затем в JavaScript мы сначала создаем наши элементы из DOM
и выбираем, какие свойства мы хотим выбрать из контактов.
const getContactsButton = document.querySelector(".get-contacts");
const contactList = document.querySelector(".contact-list");
const props = ["name", "tel", "icon"];
const options = {multiple: true};
Теперь мы асинхронно выбираем контакты, когда пользователь нажимает кнопку getContactsButton
.
const getContacts = async () => {
try {
const contacts = await navigator.contacts.select(props, options);
} catch (error) {
console.error(error);
}
};
getContactsButton.addEventListener("click", getContacts);
Используя манипуляции с DOM
, мы можем затем добавить элемент списка к каждому контакту и значок к элементу contactList
.
const appendContacts = (contacts) => {
contacts.forEach(({name, tel, icon}) => {
const contactElement = document.createElement("li");
contactElement.innerText = `${name}: ${tel}`;
contactList.appendChild(contactElement);
});
};
const getContacts = async () => {
try {
const contacts = await navigator.contacts.select(props, options);
appendContacts(contacts);
} catch (error) {
console.error(error);
}
};
getContactsButton.addEventListener("click", getContacts);
Добавление изображения немного сложнее, поскольку нам нужно будет преобразовать его в URL-адрес и добавить к каждому элементу в списке.
const getIcon = (icon) => {
if (icon.length > 0) {
const imageUrl = URL.createObjectURL(icon[0]);
const imageElement = document.createElement("img");
imageElement.src = imageUrl;
return imageElement;
}
};
const appendContacts = (contacts) => {
contacts.forEach(({name, tel, icon}) => {
const contactElement = document.createElement("li");
contactElement.innerText = `${name}: ${tel}`;
contactList.appendChild(contactElement);
const imageElement = getIcon(icon);
contactElement.appendChild(imageElement);
});
};
const getContacts = async () => {
try {
const contacts = await navigator.contacts.select(props, options);
appendContacts(contacts);
} catch (error) {
console.error(error);
}
};
getContactsButton.addEventListener("click", getContacts);
И вот результат:
Примечание. API выбора контактов будет работать только в том случае, если контекст защищен, т. е. страница обслуживается по URL-адресам https://
или wss://
.
Заключение
Итак, четыре веб-API, которые, как я считаю, позволят нам создавать более полезные и надежные PWA, но для многих из нас они ускользнули из поля зрения. Это, конечно, связано с непоследовательной поддержкой браузеров, поэтому я надеюсь, что эта статья поможет привлечь внимание к новым API, чтобы у нас было больше шансов увидеть их в будущих обновлениях браузеров.
Разве они не интересны? Мы увидели, насколько сильно мы можем контролировать ориентацию устройства и его экрана, а также уровень доступа, который мы получаем для доступа к аппаратным функциям устройства, то есть вибрации, и информации из других приложений для использования в нашем собственном пользовательском интерфейсе.
Но, как я уже говорил ранее, существует своего рода бесконечный цикл, в котором недостаточная осведомленность порождает отсутствие поддержки браузеров. Итак, хотя четыре рассмотренных нами API очень интересны, ваш опыт неизбежно будет меняться, когда дело доходит до их использования в производственной среде. Пожалуйста, действуйте осторожно и обратитесь к Caniuse для получения последней информации о поддержке или проверьте свои собственные устройства с помощью WebAPI Check.