Как из одной вкладки приложения передать информацию в другую?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Передача данных между вкладками браузера
Способы коммуникации между вкладками
В браузере существует несколько способов обмена информацией между открытыми вкладками одного сайта:
1. localStorage (Простой способ)
localStorage — это хранилище данных, общее для всех вкладок одного домена:
// Вкладка 1: отправляем данные
localStorage.setItem('userInfo', JSON.stringify({
id: 123,
name: 'John Doe'
}));
// Вкладка 2: получаем данные
const userInfo = JSON.parse(localStorage.getItem('userInfo'));
console.log(userInfo); // { id: 123, name: 'John Doe' }
Проблема: localStorage синхронное хранилище, нет события при изменении в другой вкладке (только в старых браузерах есть storage event).
2. Storage Event (Рекомендуемый способ)
Storage Event — это событие, которое срабатывает в других вкладках при изменении localStorage:
// Вкладка 1: отправляем данные
function sendDataToOtherTabs(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
sendDataToOtherTabs('notification', {
message: 'Пользователь вошел в систему',
timestamp: Date.now()
});
// Вкладка 2: слушаем изменения
window.addEventListener('storage', (e) => {
if (e.key === 'notification') {
const data = JSON.parse(e.newValue);
console.log('Получено:', data.message);
}
});
Важно: Storage Event срабатывает только в других вкладках, не в той, которая изменила localStorage.
3. Broadcast Channel API (Современный способ)
BroadcastChannel — это API для коммуникации между вкладками одного домена:
// Создаём канал коммуникации
const channel = new BroadcastChannel('user_updates');
// Вкладка 1: отправляем сообщение
function loginUser(user) {
// Логика входа...
// Отправляем информацию в другие вкладки
channel.postMessage({
type: 'USER_LOGIN',
payload: {
userId: user.id,
userName: user.name,
loginTime: new Date()
}
});
}
// Вкладка 2: слушаем сообщения
channel.addEventListener('message', (event) => {
if (event.data.type === 'USER_LOGIN') {
console.log('Пользователь вошел:', event.data.payload.userName);
updateUIWithUserInfo(event.data.payload);
}
});
// Когда вкладка закрывается
window.addEventListener('beforeunload', () => {
channel.close();
});
Преимущества:
- Простой API для обмена сообщениями
- Работает только в других вкладках
- Поддерживается всеми современными браузерами
4. SharedWorker (Для сложных сценариев)
SharedWorker — это worker, который может быть общим для нескольких вкладок:
// shared-worker.js (отдельный файл)
const connections = [];
self.addEventListener('connect', (e) => {
const port = e.ports[0];
connections.push(port);
port.addEventListener('message', (event) => {
// Рассылаем сообщение всем подключенным вкладкам
connections.forEach(p => {
if (p !== port) {
p.postMessage(event.data);
}
});
});
port.start();
});
// В каждой вкладке
const worker = new SharedWorker('shared-worker.js');
// Вкладка 1: отправляем данные
worker.port.postMessage({
type: 'UPDATE_THEME',
theme: 'dark'
});
// Вкладка 2: слушаем
worker.port.addEventListener('message', (event) => {
if (event.data.type === 'UPDATE_THEME') {
applyTheme(event.data.theme);
}
});
worker.port.start();
5. Service Worker с Message Channel
Для более надежной коммуникации можно использовать Service Worker:
// Вкладка 1: отправляем через Service Worker
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage({
type: 'BROADCAST',
data: {
event: 'SYNC_DATA',
payload: { /* данные */ }
}
});
});
// service-worker.js
self.addEventListener('message', (event) => {
if (event.data.type === 'BROADCAST') {
// Транслируем во все clients (все вкладки)
self.clients.matchAll().then(clients => {
clients.forEach(client => {
client.postMessage(event.data);
});
});
}
});
// Вкладка 2: слушаем
navigator.serviceWorker.addEventListener('message', (event) => {
if (event.data.type === 'BROADCAST') {
console.log('Получено:', event.data.data);
}
});
6. IndexedDB (Для большого объема данных)
Если нужно передать много данных, используй IndexedDB с Storage Event:
// Вкладка 1: сохраняем большой объем данных
async function saveLargeData(data) {
const db = await openIndexedDB();
const tx = db.transaction('cache', 'readwrite');
await tx.store.put({ id: 'main_data', value: data });
// Уведомляем другие вкладки
localStorage.setItem('db_update', Date.now().toString());
}
// Вкладка 2: получаем данные
window.addEventListener('storage', async (e) => {
if (e.key === 'db_update') {
const db = await openIndexedDB();
const tx = db.transaction('cache', 'readonly');
const data = await tx.store.get('main_data');
console.log('Получены данные из IndexedDB:', data.value);
}
});
Сравнение способов
| Способ | Простота | Производительность | Размер данных | Поддержка |
|---|---|---|---|---|
| localStorage + Storage Event | Высокая | Хорошо | Ограничен (5-10 МБ) | Везде |
| BroadcastChannel | Высокая | Отлично | Хороший | Современные браузеры |
| SharedWorker | Средняя | Отлично | Хороший | Не все браузеры |
| Service Worker | Сложная | Отлично | Хороший | Современные браузеры |
| IndexedDB | Средняя | Отлично | Очень большой | Везде |
Практический пример: Синхронизация темы
class ThemeSync {
constructor() {
this.channel = new BroadcastChannel('theme_channel');
this.init();
}
init() {
// Слушаем изменения темы из других вкладок
this.channel.addEventListener('message', (e) => {
if (e.data.type === 'THEME_CHANGED') {
this.applyTheme(e.data.theme);
}
});
}
setTheme(theme) {
// Сохраняем локально
localStorage.setItem('theme', theme);
// Применяем
this.applyTheme(theme);
// Уведомляем другие вкладки
this.channel.postMessage({
type: 'THEME_CHANGED',
theme: theme
});
}
applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
}
}
const themeSync = new ThemeSync();
themeSync.setTheme('dark');
Итоги
Рекомендуемый выбор:
- Просто и легко: localStorage + Storage Event
- Современно и надежно: BroadcastChannel API
- Большие объемы: IndexedDB + Storage Event
- Сложная синхронизация: Service Worker + Message Channel
Для большинства случаев BroadcastChannel — это лучший выбор: простой API, хорошая производительность и полная поддержка современных браузеров.