Подія beforeunload
beforeunload це подія, яка спрацьовує перед вивантаженням (unload) поточної сторінки з пам'яті браузера. Вона виникає, коли користувач закриває вкладку чи вікно, перезавантажує сторінку або переходить за посиланням чи вводить новий URL.
Теорія
TL;DR
- Слухається на
window, спрацьовує перед вивантаженням сторінки. event.preventDefault()разом ізevent.returnValue = ''показує стандартний діалог підтвердження виходу.- Власний текст діалогу задати не можна, браузери його ігнорують.
- Діалог варто показувати лише тоді, коли справді є незбережені зміни.
- Асинхронні дії (
fetch, таймери) тут не встигають; синхронний запис уlocalStorageвстигає. beforeunloadможна скасувати,unloadуже ні.
Швидкий приклад
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.returnValue = ''; // обов'язково!
});Після цього браузер покаже діалог підтвердження виходу:
Ви справді хочете покинути сторінку? Введені дані можуть бути втрачені.
Важливо:
- Сучасні браузери не дозволяють задавати свій текст у цьому вікні. Раніше можна було написати
event.returnValue = 'Ви впевнені?', але тепер це ігнорується. - Так зроблено заради безпеки та UX, щоб сайти не могли тиснути на користувача повідомленнями на кшталт «залишайтеся з нами».
Коли використовувати
Використовується, якщо користувач може втратити незбережені зміни, наприклад:
- редагує текст, але не натиснув «Зберегти»;
- заповнює форму;
- пише коментар;
- робить щось у застосунку з незбереженим станом.
let formChanged = false;
document.querySelector('form').addEventListener('input', () => {
formChanged = true;
});
window.addEventListener('beforeunload', (e) => {
if (formChanged) {
e.preventDefault();
e.returnValue = '';
}
});Тепер, якщо користувач змінив форму і намагається піти, з'явиться попередження.
Тихий hook перед виходом, без діалогу
Якщо треба просто виконати очищення або якусь логіку перед вивантаженням, без діалогу:
window.addEventListener('beforeunload', () => {
localStorage.setItem('lastVisited', new Date().toISOString());
});Ця подія, остання точка, де можна зберегти дані в localStorage або sessionStorage.
Різниця між beforeunload і unload
| Подія | Коли спрацьовує | Чи можна зупинити вихід | Коли використовувати |
|---|---|---|---|
beforeunload | Перед вивантаженням | Так, через preventDefault() | Попередження про незбережені дані |
unload | Після початку вивантаження | Ні | Очищення, аналітика, логування |
Обмеження
- Не можна використовувати
alert()абоconfirm()всерединіbeforeunload, браузери їх блокують. - Не варто запускати асинхронні операції (запити,
fetch), вони не встигнуть завершитися. Для аналітики єnavigator.sendBeacon(). - Працює лише у вікні або вкладці браузера, а не у фреймах.
- Краще не вішати без потреби, це UX-спам. Багато браузерів взагалі не покажуть діалог, якщо користувач ще не взаємодіяв зі сторінкою.
Підсумок
| Що робить | Подія beforeunload |
|---|---|
| Коли спрацьовує | Перед тим, як користувач покине сторінку |
| Для чого потрібна | Попередити про втрату незбережених даних |
| Як зупинити вихід | event.preventDefault() плюс event.returnValue = '' |
| Свій текст | Не можна, браузер покаже стандартний |
| Коли не підходить | Для асинхронних дій, вони не встигнуть виконатися |
Запам'ятати просто:
beforeunloadце «останній шанс» сказати браузеру: «Стій! У користувача є незбережені дані.»
Типові помилки
- Вішати обробник безумовно. Діалог на кожному виході дратує і нічого не захищає. Ставте прапорець «є незбережені зміни» і перевіряйте його всередині обробника.
- Забувати
event.returnValue = ''. У частині браузерів самогоpreventDefault()мало, і діалог просто не з'явиться. - Розраховувати на власний текст. Рядок, повернутий з обробника або записаний у
returnValue, більше ніде не показується. - Слати аналітику через
fetch. Запит обірветься разом зі сторінкою. Для цього існуєnavigator.sendBeacon(), який браузер доставить уже після вивантаження. - Не знімати обробник після збереження. Після успішного
submitтреба скинути прапорець або викликатиremoveEventListener, інакше користувач побачить попередження вже після того, як дані збережено. - Покладатися на
unload. Він не гарантовано спрацьовує на мобільних і ламає bfcache, тому кеш назад та вперед перестає працювати. Для збереження стану надійніше слухатиvisibilitychangeзі станомhidden.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.