Система уведомлений о событиях на сайте (на примере аудиоплееера ВКонтакте)

в 16:22, , рубрики: localStorage, Веб-разработка, вкладки браузера, уведомления, метки: , ,

Приветствую.

Думаю, многие, кто имеет аккаунт ВКонтакте и слушает там музыку, замечали, что если на одной вкладке включить трек, а затем уже на другой включить второй, первый трек уйдет в паузу. Примерно то же самое происходит с различными уведомлениями (новое сообщение, ответ на комментарий/запись и т.д.) — отображается оно только в активной вкладке. Кому интересно как это работет и каким образом сделать подобное у себя на сайте, милости просим за хабракат.

Теория

А реализуется всё это с помощью 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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js