Существует более 97 веб-API, и вы используете только 5 % из них. Давайте откроем остальные 95 процентов!

Совершив долгую прогулку по темным царствам спецификации, я понял, что существует так много технологий, которые не учитываются.

Моя цель с этой статьей состоит в том, чтобы вывести их на свет. И я докажу вам на практических примерах, что некоторые API действительно стоят того!

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

📑 Содержание

Предупреждение о портретном режиме

Экран слишком узкий. попробуй в ландшафтном режиме.

Некоторые приложения, такие как нелинейные видеоредакторы, не предназначены для вертикальных устройств: они просто плохо работают на узких экранах!

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

Было бы неплохо, если бы мы могли предупреждать наших пользователей, когда их устройство повернуто в неправильном направлении? Позвольте представить вам… Screen Orientation API!

Во избежание ошибок важно проверить поддержку API ориентации экрана. Это так же просто, как: if ('orientation' in screen). Вы будете видеть этот шаблон снова и снова на протяжении всей этой статьи.

API ориентации экрана

Браузеры предоставляют глобальную переменную с именем screen, которую мы будем использовать для доступа к необходимой нам информации. Доступ к экземпляру [ScreenOrientation](https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation) можно получить с помощью screen.orientation. Мы будем работать с этим объектом на протяжении всего этого раздела.

Определение ориентации экрана

Типы и углы ориентации экрана: https://w3c.github.io/screen-orientation/#dfn-screen-orientation-values-table

Вопреки распространенному мнению, существует четыре способа ориентации экрана, как показано на рисунке выше. Но нас интересует только то, находится ли экран в портретном или ландшафтном режиме, и легко написать функцию, которая сообщает нам именно это:

function getOrientation() {  
    const isPortrait = screen.orientation.type.startswith('portrait')  
    return isPortrait ? 'portrait' : 'landscape'
}

Блокировка ориентации экрана

Нативные приложения, такие как Instagram, блокируют ориентацию экрана, пока он используется. Поскольку грань между PWA и нативными приложениями с каждым днем ​​становится все более размытой, неудивительно, что эта функция также доступна в Интернете.

Хотя менее поддерживается, также можно заблокировать и разблокировать ориентацию экрана с помощью этого фрагмента кода:

screen.orientation.lock(orientation)

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

Сделайте ваш сайт полноэкранным

Браузеры закрывают наши сайты множеством элементов пользовательского интерфейса, отвлекая пользователя от того, что важно.

Снимок экрана мобильного устройства Chrome с выделением элементов пользовательского интерфейса браузера.

Это особенно проблема, когда речь идет об иммерсивном контенте, таком как:

  • кино,
  • игры,
  • максимизация изображений.

и этот список можно продолжать и продолжать.

К счастью, Полноэкранный API приходит и спасает положение!

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

Вход в полноэкранный режим

Удивительно, но любой элемент DOM может перейти в полноэкранный режим:

el.requestFullscreen()

Однако в большинстве случаев мы хотим, чтобы вся страница отображалась в полноэкранном режиме. Доступ к корневому элементу документа -<html>- можно получить в JavaScript с помощью document.documentElement.

Поэтому нет ничего необычного в том, чтобы увидеть этот фрагмент кода, гуляющий по сети:

document.documentElement.requestFullscreen()

Выход из полноэкранного режима

Существует множество способов выхода. Некоторые из них являются сочетаниями клавиш браузера по умолчанию: ESC и F11.

Также есть возможность выйти, переключая вкладки Ctrl+Tab или перескакивая через окна Alt+Tab.

Однако наиболее важным механизмом ухода является тот, который предоставляете вы — разработчик. Вы можете программно выйти из полноэкранного режима следующим образом:

document.exitFullscreen()

Однако в среде развертывания важно избегать ошибок, проверяя, существует ли эта функция перед ее вызовом:

if (document.exitFullscreen) {    
    document.exitFullscreen()
}

Проверка, находится ли пользователь в полноэкранном режиме

Если бы мы хотели реализовать полноэкранный переключатель, как показано в Codepen в начале, нам нужен был бы способ определить, активен ли полноэкранный режим.

Это вполне возможно с помощью следующего фрагмента кода:

document.fullscreenElement 
// returns 'null' or the fullscreen-enabled DOM element

Для лучшей совместимости браузера нам пришлось бы проверять несколько атрибутов:

document.fullscreenElement    
    || document.mozFullscreenElement    
    || document.msFullscreenElement    
    || document.webkitFullscreenElement

Имея это в руках, мы можем реализовать полноэкранный переключатель:

function toggleFullScreen() { 
    if (!document.fullscreenElement) {   
        document.documentElement.requestFullscreen(); 
    } else {  
        if (document.exitFullscreen) {   
            document.exitFullscreen();  
        } 
    }
}

Анимация элемента при входе в область просмотра

Подумайте о том, сколько раз вам нужно было что-то сделать, когда элемент появляется в поле зрения:

Одним из наивных решений является вызов getBoundingClientRect при каждом событии прокрутки. И я имею в виду... это работает!

Однако это ужасно неэффективно. Он работает в основном потоке, поэтому чем больше прослушивателей событий мы регистрируем, тем медленнее становится наше приложение.

К счастью, разработчики браузеров благословили нас Intersection Observer API: эффективное решение, которое делегирует все оптимизации браузеру, чтобы мы — веб-разработчики — могли сосредоточиться на том, что важно.

Мы собираемся сделать довольно крутой эффект, при котором текстовые элементы выделяются только тогда, когда они попадают в поле зрения, создавая гладкую и современную анимацию, которую оценят наши читатели. Увидьте это своими глазами в Кодексе выше.

Создание наблюдателя

Прежде чем мы начнем прослушивать события пересечения, мы должны создать объект observer, который обрабатывает все фоновые задачи:

const options = {  
    root: null, // use viewport  
    threshold: 0.75
}

const observer = new IntersectionObserver(callback, options)

Возможно, вы заметили threshold. Это параметр, который указывает браузеру запускать события пересечения только тогда, когда видим N% элемента.

Обработка событий пересечения

Давайте определим обратный вызов, функцию, которая будет вызываться при возникновении события пересечения.

Мы хотим обрабатывать событие только тогда, когда элемент отображается как минимум N% в области просмотра:

function callback(entry) {
  if (entry.intersectionRatio > 0.75) {
    // ...
  }
}

Пришло время решить, что делать с элементом, когда он попадает в поле зрения. В этом случае мы просто присвоим ему имя класса .active, а ответственность за анимацию делегируем CSS.

function callback(entry) {
  if (entry.intersectionRatio > 0.75) {
    entry.target.classList.add('active')
  }
}

Мы также можем «отменить» этот эффект, как только он покинет экран:

function callback(entry) {
  if (entry.intersectionRatio > 0.75) {
    entry.target.classList.add('active')
  } else {
    entry.target.classList.remove('active')
  }
}

Для более глубокого ознакомления с IntersectionObserver API прочтите эту потрясающую статью Дениса Мишунова.

Предотвращение затемнения экрана

Приостановлено видео космического запуска на Youtube, показывающее элементы управления видеоплеером.

Длинные видео требуют, чтобы экран оставался включенным даже без какого-либо взаимодействия. Такое поведение обычно наблюдается в нативных приложениях, но с Screen Wake Lock API это происходит и в Интернете!

Есть много других вариантов использования этого API:

  • Онлайн игры,
  • Презентации,
  • Рисунок на холсте,
  • камера,
  • Потоковое,
  • Таймеры.

и этот список никогда не заканчивается.

Давайте углубимся в его внутреннюю работу!

Firefox и Safari еще не поддерживают эту функцию. Так что всегда полезно сначала проверить его доступность, чтобы избежать всевозможных ошибок: if («wakelock» в навигаторе)

Приобретение wakelock

Видеоплеер, такой как Youtube, может получить wakelock в своей функции play:

let wakelock = null

async function play() {
    // … 
    wakelock = await navigator.wakeLock.request('screen')
}

Если батарея пользователя слишком разряжена, ожидайте, что она выйдет из строя.

Снятие пробуждения

Плохая практика — оставлять вейклок навсегда, так как это повредит аккумулятор пользователя и может даже снизить производительность. Поэтому обязательно всегда выпускайте его, когда это возможно:

async function pause() {
  // ...
  await wakelock.release()
}

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

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

Но в двух словах, он срабатывает, когда пользователь покидает/заходит на вкладку веб-сайта.

document.addEventListener('visibilitychange', async () => {  
    if (wadocument.addEventListener('visibilitychange', async () => {  
    if (wakelock !== null && document.visibilityState === 'visible') {    
        wakelock = await navigator.wakeLock.request('screen')  
    }
})

Запись вашего экрана

Появляется все больше веб-приложений для записи экрана. Но как именно они это делают? Ответ на удивление прост.

Секрет их успеха — Screen Capture API, простой в использовании интерфейс, который позволяет пользователям записывать свой экран самыми разными способами:

  • Весь экран,
  • Конкретное окно,
  • Конкретная вкладка.

Он также поставляется с дополнительными изящными функциями, включая, помимо прочего:

  • размытие/закрытие перекрывающихся окон, чтобы избежать случайного обмена конфиденциальной информацией,
  • скрыть/показать курсор,
  • запись звука.

Совместимость с браузером

Ненавижу быть вестником плохих новостей, но пока ни один мобильный браузер не поддерживает этот API.

С другой стороны, он очень хорошо поддерживается современными настольными навигаторами! (кроме Internet Explorer, разумеется)

Начальный снимок экрана

Благодаря этому восторгу от API запись экрана становится невероятно простой:

const options = {
    video: {
        cursor: 'always' // show the cursor
    },
    audio: false // don't record audio
}
navigator.mediaDevices.getDisplayMedia(options) // returns a promise

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

Подсказка о снимке экрана, показывающая 3 типа: весь экран, окно, вкладка.

Вышеупомянутая функция сообщает браузеру о необходимости выбора желаемой поверхности для записи, как показано на изображении выше. (попробуйте сами в codepen на старте этого раздела)

Предварительный просмотр записи

Было бы неплохо, если бы мы могли видеть именно то, что видит веб-сайт. К счастью, это ужасно легко сделать:

<video autoplay id="preview"></video>

И это было все для HTML. Теперь давайте перейдем к логике JavaScript:

previewElem = document.getElementById('preview')
previewElem.srcObject = await navigator.mediaDevices.getDisplayMedia(options)

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

Остановка захвата экрана

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

let tracks = previewElem.srcObject.getTracks()

tracks.forEach(() => track.stop())
previewElem.srcObject = null

Хранение табличных данных в базе данных на устройстве

Прямо в вашем браузере скрыта целая система баз данных NoSQL, и доступ к ней осуществляется с помощью API IndexedDB!

Каждая операция является асинхронной, поэтому она никогда не замедляет другие операции. Он также очищается, когда пользователь стирает кеш браузера или локально хранящиеся данные.

В дополнение ко всему этому, он также поддерживает обычные действия поиска, получения и размещения с транзакциями на стороне. Он может хранить практически все виды данных, включая, помимо прочего, File, изображения и видео как Blob и, конечно же, String.

К сожалению, не все браузеры согласны с тем, какие типы данных должны поддерживаться. Например, Safari на iOS не может хранить данные BLOB-объектов. Однако можно преобразовать все другие форматы в ArrayBuffer, что очень хорошо поддерживается всеми платформами.

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

Есть много вещей, которые мы можем сделать с этим API, включая, но не ограничиваясь:

  • Хранение структурированных данных для автономного использования,
  • Ускорение времени загрузки при повторных посещениях,
  • Кэширование пользовательских данных,
  • Временное сохранение данных перед их загрузкой на сервер.

Давайте посмотрим, как мы можем хранить контактные данные в IndexedDB!

Использование ИндекседБД

Прежде чем мы сможем что-либо сделать, мы должны использовать библиотеку-оболочку поверх IndexedDB, потому что по умолчанию это слишком сложно; он использует события вместо обещаний.

import { openDB } from 'idb';

const db = await openDB('contacts', 1, {
    // Creates a new database if it doesn't exist.
    upgrade(db) {
        db.createObjectStore('contacts', {
            // The 'id' property of the object will be the key.
            keyPath: 'id',
            // If it isn't explicitly set, create a value by auto incrementing.
            autoIncrement: true,
        })

        // Create an index on the 'name' property of the objects.
        store.createIndex('name', 'name');
    }
})

И после этого мы можем начать хранить структурированные данные, как будто это никого не касается!

await db.add('contacts', {
    name: 'John Doe',
    age: 25,
    email: '[email protected]'
})

И мы можем так же легко получить все это:

// Get all contacts in name order:
const contacts = await db.getAllFromIndex('contacts', 'name')

Это все, что нам нужно знать для нашего простого варианта использования. Но если вам все же интересно, вы можете углубиться в документацию.

Сохранение текстовых данных на устройстве, даже когда пользователь уходит

Хотя мы можем использовать IndexedDB для хранения больших и сложных данных в браузере, все же важно учитывать и другие случаи, когда все, что нам нужно сохранить, — это простая пара ключ-значение:

  • данные для входа,
  • Состояние подписки на рассылку,
  • согласие на использование файлов cookie,
  • Пиксели отслеживания аналитики.

Важно отметить, что конфиденциальную информацию (пароли, данные кредитной карты, номера социального страхования и т. д.) НИКОГДА не следует сохранять в браузере, поскольку он уязвим для XSS-атак в дополнение к другим эксплойтам.

Для таких простых случаев есть специальный инструмент, который называется Web Storage API. И так же, как IndexedDB, он привязан к конкретному поддомену. Он также очищается, если пользователь очищает кэш или данные браузера.

В этом API вы найдете два типа хранилища: localStorage и sessionStorage. Они предлагают различные преимущества:

  • Локальное хранилище сохраняет данные, даже когда пользователь покидает веб-сайт, в отличие от хранилища сеанса, которое очищает все данные, как только вкладка закрывается.
  • Локальное хранилище может хранить больше данных, в отличие от хранилища сеансов, максимальный размер которого составляет 5 МБ.

Использование локального хранилища

Допустим, мы внедряем форму подписки на рассылку новостей. Мы не хотим показывать его пользователю даже после того, как он подписался, поэтому мы будем использовать глобальную переменную localStorage для условного отображения:

function subscribe() {
    // ...
    localStorage.setItem('is-newsletter-subscribed', true)
}

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

А теперь давайте напишем функцию, которая решает, показывать форму подписки или нет:

function isSubscribed() {
    return localStorage.hasOwnProperty('is-newsletter-subscribed') ? localStorage.getItem('is-newsletter-subscribed') : false
}

Как видите, сначала мы проверяем, существует ли элемент newsletter-subscribed. Если это так, мы просто возвращаем его значение, используя getItem(), в противном случае мы возвращаем false, потому что пользователь еще не подписался.

Создание волнового эффекта с учетом местоположения

С развитием Интернета выросли и спецэффекты. В наши дни свойств CSS недостаточно для реализации наших самых смелых желаний.

Раньше нашим последним средством были GIF-файлы и изображения, но с CSS Painting API это уже не так!

Теперь мы можем использовать все стильные эффекты HTML Canvas, чтобы рисовать что угодно на фоне элемента.

Совместимость с браузерами не очень. Firefox и Safari на iOS еще не поддерживают его. Поэтому очень важно запустить следующее: if ('paintWorklet' in CSS)

Давайте создадим волновой эффект без каких-либо псевдоэлементов, вдохновленный собственной реализацией Google.

Логика JavaScript

Чтобы этот эффект работал, нам нужно использовать события JavaScript, чтобы получить позиции курсора x и y:

// index.js

button.addEventListener('click', (e) => {
    const {x: offsetX, y: offsetY} = button.getBoundingClientRect()
    const [x, y] = [e.clientX - offsetX, e.clientY - offsetY]

    button.style.setProperty('--x', x)
    button.style.setProperty('--y', y)
    // ...
})

Поскольку волновой эффект — это анимация, которая развивается во времени, нам нужно отслеживать ее временную шкалу с помощью переменной tick:

// index.js

button.addEventListener('click', (e) => {
    // ...

    const start = performance.now()
    requestAnimationFrame(function step(now) {
        const tick = Math.floor(now - start)
        button.style.setProperty('--tick', tick)

        // Continue animation
        requestAnimationFrame(step)
    })
})

В приведенном выше коде используется [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) для создания эффективной и оптимизированной анимации. На каждом шаге анимации мы вычисляем «тик» и присваиваем его свойству CSS.

Если мы оставим его так, он будет работать вечно. Итак, давайте добавим «конечное условие», чтобы закончить анимацию. Мы остановим его, когда он достигнет 1 секунды (то есть 1000 миллисекунд):

// index.js

button.addEventListener('click', (e) => {
    // ...

    requestAnimationFrame(function step(now) {
        const tick = Math.floor(now - start)
        button.style.setProperty('--tick', tick)

        // Stop the animation after 1 second
        if (tick > 1000) {
            button.style.setProperty('--tick', 0)
            return
        }

        // Continue animation
        requestAnimationFrame(step)
    })
})

И это все для логики!

Рабочий покраски

Давайте создадим настоящий волновой эффект, используя Paint API.

Этот эффект должен находиться в отдельном файле, который мы назовем ripple.js.

Начнем с получения свойств CSS, которые мы только что определили:

// ripple.js

registerPaint('ripple', class {
    static get inputProperties() {
        return ['--x', '--y', '--tick']
    }
})

Далее мы будем использовать Canvas API, чтобы нарисовать круг на фоне кнопки:

// ripple.js

registerPaint('ripple', class {
    //...

    paint(ctx, {width}, props) { 
        // Retrieve props
        const x = parseFloat(props.get('--x').toString())
        const y = parseFloat(props.get('--y').toString())
        let tick = parseFloat(props.get('--tick').toString())

        // Clamp tick in [0, 1000]
        if (tick < 0) tick = 0
        if (tick > 1000) tick = 1000

        // Draw ripple
        const rippleColor = 'rgba(255,255,255,0.54)'
        ctx.fillStyle = rippleColor
        ctx.globalAlpha = 1 - tick/1000
        ctx.arc(
            x, y, // center
            width * tick/1000, // radius
            0, 2 * Math.PI // full circle
        )

        ctx.fill()
    }
})

Регистрация покрасочной работы

Вернитесь в свой файл index.js и добавьте следующий код:

// index.js

if ('paintWorklet' in CSS) {
    CSS.paintWorklet.addModule('ripple.js')
}

Сначала он проверит, поддерживается ли CSS Paint API, и только потом свяжет волновой эффект.

Готово! Осталось только использовать этот эффект. Поэтому добавьте следующий код в свой CSS:

button {
    background-color: #0d1117;
    background-image: paint(ripple);
}

Для более глубокого ознакомления с CSS Paint API прочитайте эту потрясающую статью Адриана Беса.

Отображение родного меню обмена

В Интернете так много контента, которым мы можем поделиться с другими:

  • ссылки,
  • изображений,
  • абзацы.

и этот список никогда не заканчивается.

Обычно разработчик реализует собственную систему обмена со ссылками на Twitter, Facebook и другие сайты социальных сетей.

Эти компоненты, однако, всегда уступают своим родным аналогам, которые имеют огромное количество опций:

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

и список, опять же, никогда не заканчивается.

Эти собственные меню общего доступа раньше были эксклюзивными для собственных приложений, но с Web Share API это уже не так.

Совместимость с браузером превосходна в мобильных браузерах, но немного сложнее, когда дело доходит до Firefox на ПК.

Попробуйте сами в Codepen выше, и если это не поддерживается вашим устройством, вот как оно может выглядеть:

Меню общего доступа с множеством опций, включая Gmail, Сообщения, Reddit и LinkedIn.

Совместное использование URL-адресов

Метод поиска — navigator.share. Он принимает объект, содержащий заголовок, строку текста и URL-адрес.

const shareData = {
  title: 'Smashing Magazine',
  text: 'Smashing Magazine — For Web Designers And Developers',
  url: 'https://www.smashingmagazine.com/'
}

await navigator.share(shareData)

Обратите внимание, что эта функция защищена временной активацией, что означает, что для ее обработки требуется событие пользовательского интерфейса (например, щелчок).

Копирование текста в буфер обмена

Буфер обмена — одна из самых недооцененных функций современных компьютеров. Смогли бы мы, разработчики, выжить без постоянного Ctrl+C кода из Stackoverflow? Сомневаюсь.

Буфер обмена предназначен для перемещения цифровой информации из точки А в точку Б. Единственная альтернатива — переписывать содержимое вручную, что создает огромные возможности для ошибок. Современные буферы обмена также позволяют копировать изображения и другие формы мультимедиа.

С появлением Clipboard API разработчики могут показать красоту UX своим пользователям, программно копируя важную информацию в буфер обмена пользователя. Эта функция также видна повсюду, от кода на веб-сайте MDN до Twitter. Его нет только в Stackoverflow, и по уважительной причине.

Совместимость с браузерами тоже отличная, кроме IE, конечно.

Использование API буфера обмена

Копировать текст очень просто:

await navigator.clipboard.writeText('Howdy, partner!')

И прочитать его так же просто:

const text = await navigator.clipboard.readText()

Совместное использование выбранного текста

Выделенный текст в блоге с всплывающей подсказкой поверх него.

Несколько блогов, таких как Medium, позволяют пользователям легко делиться выбранным текстом с другими социальными платформами.

Будучи такой полезной функцией, она поощряет обмен контентом и, как следствие, расширяет блог до огромных размеров.

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

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

И не нужно беспокоиться о браузерной совместимости, потому что она просто идеальна!

Получение выделенного текста

Это ужасно легко сделать:

const text = window.getSelection().toString()

Вот и все! Теперь перейдите к предыдущему разделу API веб-ресурсов, чтобы открыть всплывающее меню общего доступа, определяемое ОС, и дайте своим пользователям волю!

Изменение заголовка, когда пользователь покидает вкладку

Название веб-сайта меняется с «Веб-сайт для покупок» на «Пожалуйста, оставайтесь», когда пользователь покидает вкладку.

Веб-сайт может определить, просматривается он или нет, с помощью Page Visibility API.

Хотя я не рекомендую использовать Page Visibility API для привлечения внимания пользователя раздражающими сообщениями, у него есть много положительных вариантов использования:

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

Совместимость с браузером не является проблемой.

Определение видимости страницы

Мы можем получить состояние видимости страницы в любое время с помощью следующего кода:

document.visibilityState // 'visible' or 'hidden'

Но реальные варианты использования требуют прослушивания событий и, соответственно, изменения некоторого поведения.

К сожалению, название события зависит от браузера, поэтому нам нужно сделать следующее:

let hidden;
let visibilityChange;
if (typeof document.hidden !== "undefined") { 
  // Opera 12.10 and Firefox 18 and later support
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}

Затем мы можем прослушивать события видимости страницы, например:

document.addEventListener(visibilityChange, handleVisibilityChange);

function handleVisibilityChange() {
  if (document[hidden]) {
    // page is hidden
  } else {
    // page is visible
  }
}

В целях демонстрации мы просто изменим название документа:

function handleVisibilityChange() {
  if (document[hidden]) {
    document.title = 'Please stay!!!'
  } else {
    document.title = 'Shopping website'
  }
}

Обратите внимание, что я не рекомендую этого делать, так как это просто раздражает пользователя и является фундаментальным нарушением этического веб-дизайна.

Заключение

В наши дни веб-API ликвидируют разрыв между веб-приложениями и нативными приложениями.

Сеть начинает становиться реальной угрозой для монополий, созданных App Store и Google Play Store, и не собирается останавливаться. Давайте обсудим это в разделе комментариев ниже!

Есть еще много API, которые мы еще не исследовали, и некоторые из них могут делать невероятные вещи, такие как сканирование штрих-кодов и даже распознавание речи! Так что ждите вторую часть! ❤️

Почетные упоминания

Было бы стыдно не упомянуть еще одну группу API, которые очень редко используются, но имеют так много интересных и практических вариантов использования:

Первоначально опубликовано на https://dev.to 23 июля 2022 г.

Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .

Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.