Page Visibility API

Page Visibility API выполняет простую, но важную функцию — он позволяет приложению знать, когда веб-страница видна пользователю. API определяет состояния видимости документа, и реагирует на изменение просмотра. В статье написаны основы PageVisibility API и показаны некоторые практические примеры.

Многие веб-разработчики интересуются возможностями новых технологий позволяющие создавать все более и более привлекательные интерактивные веб-страницы, например 3D графику с WebGL или расширить возможности аудио средствами WebAudio. Конечно приложение getUserMedia использующие веб-камеру и микрофон в реальном времени очень интересное. Но, есть не менее интересные технологии которые могут впечатлить пользователя интернета.

На первый взгляд для удобства в использовании Page Visibility API может показаться не очень полезным, но учитывая огромный рост мобильных устройств, все что помогает экономить заряд батареи устройства, становится очень важным. С помощью Page Visibility API ваш сайт может помочь устройствам пользователей потреблять энергии меньше, тем самым служит дольше.

Рассмотрим некоторые возможности:

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

Свойства отображения документа

Текущая версия спецификаций Page Visibility API определяет два свойства документа: boolean hidden и visibilityState. Настройки visibilityState, в настоящее время может имеет четыре возможных значения: hidden, visibility, prerender и unloaded.

для поздних версий браузеров требуется к свойствам добавить префиксы: webkitHidden и webkitVisibilityState.

Если документ не видно вообще, т.е. пользователь перешел на другую закладку в браузере, значение возвращает true. Если атрибут имеет значение false значить пользователь просматривает веб-страницу. Еще атрибут скрытия может принимать значение false, когда средство специальных возможностей Экранная лупа полностью закрывает документ.

к меню ↑

Работа с префиксами

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

function getHiddenProp(){
  var prefixes = ['webkit','moz','ms','o'];

  // если скрыто поддерживается только return
  if ('hidden' in document) return 'hidden';

  // перебрать все известные префиксы пока не найдем нужный
  for (var i = 0; i < prefixes.length; i++){
  if ((prefixes[i] + 'Hidden') in document)
  return prefixes[i] + 'Hidden';
  }

  // это не поддерживается
  return null;
  }
к меню ↑

Пример свойств документа

Теперь мы можем написать кроссбраузерные функции, isHidden(), чтобы знать когда документ виден.

function isHidden() {
    var prop = getHiddenProp();
    if (!prop) return false;

    return document[prop];
}

Для более детального просмотра отображаемого документа, вы можете использовать свойства visibilityState. Это свойство возвращает одно из четырех значений:

  • hidden — документ полностью скрыт
  • visibility — документ частично виден
  • prerender — документ загружается вне экрана но его не видно (это значение не является обязательным, не все браузеры будут это поддерживать)
  • unloaded — если документ должен быть выгружен, то значение будет возвращено (это значение не является обязательным, не все браузеры будут это поддерживать)
к меню ↑

Событие visibilitychange

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

// использование свойств для генерации событий
  var visProp = getHiddenProp();
  if (visProp) {
  var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
  document.addEventListener(evtname, visChange);
  }

  function visChange() {
  var txtFld = document.getElementById('visChangeText');

  if (txtFld) {
  if (isHidden())
  txtFld.value += "Tab Hidden!\n";
  else
  txtFld.value += "Tab Visible!\n";
  }
}

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

 

(Если вы увидите текст PageVisibilityAPI не поддерживается!, значит ваш браузер не поддерживает этот API)

к меню ↑

Практические примеры

Воспроизведение и пауза в видео

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

Это определяется путем обращений к событиям visibilityChange, а затем происходит переключение состояния видео кодом:

window.addEventListener("load", function vidDemo() {
  sessionStorage.initialPlay = false;
  var vidElem = document.getElementById("video-demo");

  var visProp = getHiddenProp();
  if (visProp) {
  vidElem.addEventListener("play", function() {
  sessionStorage.initialPlay = true;
  });

  var evtName = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
  document.addEventListener(evtName, startStopVideo);
  }

  function startStopVideo() {
  if (document[visProp]) {
  vidElem.pause();
  }
  else if (vidElem.paused && sessionStorage.initialPlay == "true") {
  vidElem.play();
  }
  }
  });
к меню ↑

Показывать уведомления когда вкладка скрыта

Web Notifications API в сочетании с PageVisibility API уведомляет пользователя о том что вкладка скрыта, хотя это очень раздражает.

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

(Сначала нажмите: Включить уведомление чтобы включить уведомление)

А вот код:

window.addEventListener("load", function notifyDemo() {
   var propName = "";
   var oNotify=null;
   var visProp = getHiddenProp();

   document.getElementById("notify-demo").addEventListener("click", function() {
      oNotify = null;
      if (window.webkitNotifications) {
         setTimeout(showNotification, 5000);

         if (window.webkitNotifications.checkPermission() == 0) { // 0 is PERMISSION_ALLOWED
            oNotify = window.webkitNotifications.createNotification('', 'Уведомление', 'Вы получили уведомление на странице http://htmlhook.ru/pagevisibility-api.html');
         }
      }
   });

   document.getElementById("notify-enable").addEventListener("click", function() {
      window.webkitNotifications.requestPermission();
   });

   function showNotification() {
      if (document[visProp] && window.webkitNotifications && oNotify) {
         oNotify.show();
      }
      else {
         alert("Уведомление о странице http://htmlhook.ru/pagevisibility-api.html");
      }
   }
});

Если не уведомления нет, значить произошли изменения в спецификации Notification API.

к меню ↑

Google Analytics, если страница pre-rendered

В браузерах, таких как Google Chrome, есть возможность предварительного рендеринга страниц (узнать больше о предварительной визуализации можно на странице Chrome). Этот процесс включает в себя загрузку всех ресурсов, необходимых для отображения страницы — в том числе любые сценарии, которые подключены к странице.

Для анализа посещаемости почти все сайты используют сервис Google Analytics, но этот анализ может быть искажен. Чтобы предотвратить это, вы можете использовать Page Visibility API, для обнаружения страницы в реальном времени и пропустить отслеживание точки просмотра. Страница должна содержать код, который выглядит следующим образом:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);

В этом случае, событие _trackPageview всегда записывается, даже если страница не отображается для пользователя. Сценарий, который определяет предварительный рендеринг будет выглядеть так:

var bHavePV = getHiddenProp();
  var bInitialShow = false;
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXX-X']);

  if (bHavePV) {
  document.addEventListener("visibilityChange", handleVisEvt);
  }
  else {
  _gaq.push(['_trackPageview']); // трек просмотра страницы обычно, когда нет PageVisibility
  }

  function handleVisEvt() {
  if (document.visibilityState == "prerender") {
  _trackEvent("pagedata", "prerender"); // возможно, будет интересно отслеживать pre-rendering
  }
  if (document.visibilityState == "visible" && !bInitialShow) {
  bInitialShow = true; // не вызывать этот код еще раз
  _gaq.push(['_trackPageview']);
  }
  }
к меню ↑

Поддержка

Большие веб-приложения должны включает в себя гораздо больше чем простые функции которые пользователи могут видеть и взаимодействовать с ними. Продуманное веб-приложение предоставляет рациональное использование ресурсов пользователем, и Page Visibility API важная составляющая часть этих приложений.

Ссылки