- PVSM.RU - https://www.pvsm.ru -
Наглядный пример задачи — сайт vk.com. Каждый раз когда вы воспроизводите музыку или видео в одной вкладке — в других вкладках воспроизведение останавливается. И если вы обратитесь в интернет за помощью в решении данной задачи, то наверняка найдете описание Storage Events [1] или Page Visibility API [2] или даже готовые решения, к примеру Visibility.js [3].
На хабре уже был обзор этих вещей, к примеру вот [4] и ещё [5].
Я прошел по этому пути, но не одно из решений меня не устроило. Мне хотелось чего-нибудь простого, легковесного и не требующего глубокого изучения деталей.
Решение, которое получилось в итоге, обрело название DuelJS (просто рандомное уникальное название) и ниже я попробую сравнить его с Visibility.js, дабы избежать лишней критики в свою сторону.
Удобная кроссбраузерная обертка для простого отражения состояния «эта вкладка сейчас активна», в visibility.js будет выглядеть следующим образом:
if ('visible' == Visibility.state()) {
// эта вкладка активна
}
У вкладки Visibility есть 3 состояния: visible, hidden и prerender.
Преимуществом Visibility также являются callbacks, которые вы можете вешать на множество событий, таких как активизация вкладки, setInterval в активном окне и тому подобное.
Философия DuelJS слегка упрощена:
1. Все вкладки имеют лишь 2 состояния — Master и Slave
2. Мастер вкладка это вкладка в которой ведется работа — ничего лишнего, все остальные есть Slave.
При таком подходе достаточно лишь одной функции: window.isMaster() — проверить является ли вкладка мастером.
if (window.isMaster()) {
// эта вкладка активна
}
Теперь перейдем к коммуникациям между вкладками. Наиболее подходящим решением мне показалось использование Storage Events [6], хотя они и не без проблем. К слову находил я в гугле еще такие варианты как использование postMessage API [7] или WebSockets.
Основная проблема Storage Events заключается в их плохой поддержке некоторыми MSIE, хотя до недавнего времени и у других браузеров тоже могли возникать с этим проблемы.
Так как Visibility.js является по сути оберткой над Page Visibility API — работа со Storage Events в ней отсутствует.
В DuejJS существует кроссбраузерная обертка над Storage Events, которая выражается в следующей философии:
1. Коммуникации между вкладками осуществляются при помощи каналов
2. Внутри канала вкладки могут запускать события, на которые могут реагировать другие вкладки в этом канале
Создать канал достаточно просто:
var ch = duel.channel('channel_name'); // channel_name - имя канала
Теперь определим поведение при вызове события qwerty:
ch.on('qwerty', function (a, b, c, ...) {})
Метод on у канала определяет его поведение. В функции, передаваемой вторым параметром может быть сколько угодно аргументов, или не быть вовсе.
Запустить событие так же легко. Слово on теперь заменим на broadcast, а передаваемые аргументы вставим после названия события:
ch.broadcast('qwerty', a, b, c, ...)
Для нетерпеливых читателей сразу даю ссылку на рабочий пример [8].
Основная суть приложения заключается в трех строках:
1. var player = duel.channel('player'); (определение канала)
2. player.on('stop', function () {… (определение поведения при событии stop)
3. player.broadcast('stop'); (запуск события stop)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Остановлено</title>
<!-- Заголовок (title) страницы отражает состояние воспроизведения. -->
<script type="text/javascript" src="duel.min.js"></script>
<link rel="stylesheet" type="text/css" href="pretty.css">
</head>
<body>
<!-- div #preview представляет из себя кликабельную картинку, при клике по которой инициализируется iframe с роликом youtube -->
<div id="preview"><div>PLAY</div></div>
<a href="index.html" target="_blank">Открыть новую вкладку</a>
<script type="text/javascript">
/** открываем канал с именем player */
var player = duel.channel('player');
/** превью для видео-ролика */
var previewDiv = document.getElementById('preview');
/**
* Регистрируем новое событие канала player
*/
player.on('stop', function () {
/**
* Удаляем iframe
*/
var frame = document.getElementsByTagName('iframe')[0];
frame.parentNode.removeChild(frame);
/**
* Показываем превью
*/
previewDiv.style.display = 'block';
/**
* Обновляем заголовок вкладки
*/
document.title = 'Остановлено';
});
previewDiv.onclick = function () {
/**
* Посылаем сигнал stop в канал player
*/
player.broadcast('stop');
/**
* Создаем новый элемент iframe с видео из youtube
*/
var frame = document.createElement("iframe");
frame.width = '859';
frame.height = '480';
frame.src = '//www.youtube.com/embed/xsV8TrF4gN0?rel=0&autoplay=1';
frame.frameborder = '0';
/**
* Встраиваем его под превью и скрываем превью
*/
previewDiv.parentNode.insertBefore(frame, previewDiv.nextSibling);
previewDiv.style.display = 'none';
/**
* Обновляем заголовок вкладки
*/
document.title = 'Играем...';
}
</script>
</body>
</html>
Буду очень рад если вам поможет данное решение и вы используете его в своих проектах. Я открыт к идеям по улучшению. Либа — кроссбраузерная и работает в том числе и в IE, за счет встроенных хаков.
Краткая документация DuelJS на сайте [9]
Репозиторий DuelJS на GitHub [10]
Ещё одна демка DuelJS [11]
Автор: student_ivan
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/79369
Ссылки в тексте:
[1] Storage Events: http://html5demos.com/storage-events
[2] Page Visibility API: https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API
[3] Visibility.js: https://github.com/ai/visibilityjs
[4] вот: http://habrahabr.ru/company/evilmartians/blog/125833/
[5] ещё: http://habrahabr.ru/post/114350/
[6] Storage Events: http://diveintohtml5.info/storage.html
[7] postMessage API: https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
[8] ссылку на рабочий пример: http://dueljs.studentivan.ru/youtube_player_example/
[9] Краткая документация DuelJS на сайте: http://dueljs.studentivan.ru
[10] Репозиторий DuelJS на GitHub: https://github.com/studentIvan/dueljs
[11] Ещё одна демка DuelJS: http://dueljs.studentivan.ru/bower_components/duel/public/
[12] Источник: http://habrahabr.ru/post/247739/
Нажмите здесь для печати.