Приветствую.
Думаю, многие, кто имеет аккаунт ВКонтакте и слушает там музыку, замечали, что если на одной вкладке включить трек, а затем уже на другой включить второй, первый трек уйдет в паузу. Примерно то же самое происходит с различными уведомлениями (новое сообщение, ответ на комментарий/запись и т.д.) — отображается оно только в активной вкладке. Кому интересно как это работет и каким образом сделать подобное у себя на сайте, милости просим за хабракат.
Теория
А реализуется всё это с помощью HTML5 Local Storage. Возьмем тот же аудиопроигрыватель. При запуске трека в Local Storage сохраняется идентификатор окна и состояние проигрывателя (к примеру, 'play'). Если в другом окне (одного и того же домена, разумеется) запускается ещё один трек, все вкладки ставят свои проигрыватели на паузу. И так далее.
Практика
Хранить данные события будем в одном ключе, к примеру, 'notifier_event'. Писать туда будет строковое представление некоего объекта следующего вида:
var evt = {
'notifier_id': 'aAr63gd2',
'event': 'audiostate',
'event_data': {'state': 'play'},
'event_ts': Math.round(new Date().getTime() / 1000)
};
Поле notifier_id — это ID вкладки, из которой было послано событие; 'event' — название события, 'event_data' — соответственно данные события, 'event_ts' — Unix Timestamp. Время ивента нужно указывать чтобы событие смены значения ключа отрабатывалось всегда.
При получении события просто запускаем необходимый обработчик и выполняем все действия, которые относятся к полученному событию. Вот и всё :)
Листинги
Обработка события
/**
* Binds storage key change event
* @return void
**/
Notifier.prototype.bindEvent = function()
{
if (!this.isAvailable())
return false;
var t = this;
$(window).bind('storage', function(e) {
var evt = e.originalEvent;
if (evt.key == t.m_localStorageKey) // Если измененный ключ - ключ хранения события, вызываем обработчика
t.handleLsEvent(JSON.parse(evt.newValue));
});
};
/**
* Handles changes for certain localStorage event
* @param Object evt
**/
Notifier.prototype.handleLsEvent = function(evt)
{
switch (evt.event)
{
case 'audiostate':
this.handleAudioStateEvent(evt); // Обработчик нажатия кнопки play/pause проигрывателя
break;
}
};
/**
* Handles audiostate event
* @param Object evt
* @return void
**/
Notifier.prototype.handleAudioStateEvent = function(evt)
{
if (evt.notifier_id != this.getNotifierId())
{
if (evt.event_data.state == 'play')
{
// Если какая-то вкладка начала проигрывание трека, ставим текущий проигрыватель на паузу
player.pause();
}
}
};
Демо
Пример можно посмотреть здесь — трек 1, трек 2.
Исходники
Исходники можно скачать из репозитория GitHub.
Представленные в демо аудиозаписи распространяются под лицензией Attribution-ShareAlike License.
Автор: Shadez