Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Подія beforeunload». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`beforeunload` спрацьовує безпосередньо перед вивантаженням поточної сторінки: коли користувач закриває вкладку, перезавантажує сторінку або переходить за посиланням.** Якщо в обробнику викликати `event.preventDefault()` і присвоїти `event.returnValue = ''`, браузер покаже стандартний діалог підтвердження виходу; свій текст задати не можна, сучасні браузери його ігнорують заради безпеки та UX. Це також остання точка, де можна синхронно щось записати в `localStorage`, бо асинхронні `fetch`-запити вже не встигнуть завершитися. ```javascript window.addEventListener('beforeunload', (event) => { if (formChanged) { event.preventDefault(); event.returnValue = ''; // обов'язково } }); ``` **Ключове:** `beforeunload` це останній шанс попередити, що в користувача є незбережені дані.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`beforeunload` це подія, яка спрацьовує перед вивантаженням (unload) поточної сторінки з пам'яті браузера.** Вона виникає, коли користувач закриває вкладку чи вікно, перезавантажує сторінку або переходить за посиланням чи вводить новий URL. ## Теорія ### TL;DR - Слухається на `window`, спрацьовує перед вивантаженням сторінки. - `event.preventDefault()` разом із `event.returnValue = ''` показує стандартний діалог підтвердження виходу. - Власний текст діалогу задати не можна, браузери його ігнорують. - Діалог варто показувати лише тоді, коли справді є незбережені зміни. - Асинхронні дії (`fetch`, таймери) тут не встигають; синхронний запис у `localStorage` встигає. - `beforeunload` можна скасувати, `unload` уже ні. ### Швидкий приклад ```javascript window.addEventListener('beforeunload', (event) => { event.preventDefault(); event.returnValue = ''; // обов'язково! }); ``` Після цього браузер покаже **діалог підтвердження виходу**: > Ви справді хочете покинути сторінку? > Введені дані можуть бути втрачені. **Важливо:** - Сучасні браузери **не дозволяють задавати свій текст** у цьому вікні. Раніше можна було написати `event.returnValue = 'Ви впевнені?'`, але тепер це ігнорується. - Так зроблено **заради безпеки та UX**, щоб сайти не могли тиснути на користувача повідомленнями на кшталт «залишайтеся з нами». ### Коли використовувати Використовується, якщо користувач може **втратити незбережені зміни**, наприклад: - редагує текст, але не натиснув «Зберегти»; - заповнює форму; - пише коментар; - робить щось у застосунку з незбереженим станом. ```javascript let formChanged = false; document.querySelector('form').addEventListener('input', () => { formChanged = true; }); window.addEventListener('beforeunload', (e) => { if (formChanged) { e.preventDefault(); e.returnValue = ''; } }); ``` Тепер, якщо користувач змінив форму і намагається піти, з'явиться попередження. ### Тихий hook перед виходом, без діалогу Якщо треба просто виконати очищення або якусь логіку перед вивантаженням, без діалогу: ```javascript 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`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.