Як я можу замінити діалогове вікно OnBeforeUnload і замінити його власним?


346

Мені потрібно попередити користувачів про незбережені зміни, перш ніж вони залишають сторінку (досить поширена проблема).

window.onbeforeunload=handler

Це працює, але воно відкриває діалог за замовчуванням із дратуючим стандартним повідомленням, яке перекриває мій власний текст. Мені потрібно або повністю замінити стандартне повідомлення, щоб текст міг бути зрозумілим, або (ще краще) замінити весь діалог модальним діалогом за допомогою jQuery.

Поки що я провалився, і я не знайшов нікого іншого, хто, здається, має відповідь. Чи можливо це навіть?

Javascript на моїй сторінці:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

Функція closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Використовуючи jQuery та jqModal, я спробував такі речі (за допомогою спеціального діалогового вікна підтвердження):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

що також не працює - я, здається, не можу прив’язатись до події перед завантаженням.


1
чи можете ви навести приклад свого поточного коду та що він виробляє?
Оуен

Оуен правильно. І причиною цього є безпека. Запобігання розвантаженню сторінки є корисним у веб-формах тощо, але це може бути легко використане шкідливим сайтом, щоб обдурити користувача залишатися на сторінці. Ось чому веб-браузери реалізують стандартне повідомлення та мають цей механізм для вставки спеціального тексту.
pluckyglen

дивіться тут для отримання додаткової інформації: stackoverflow.com/questions/140460
Бен Макінтайр

Більш детальна інформація: stackoverflow.com/questions/7389554/crossbrowser-onbeforeunload / ...
Aelios

1
НЕ представляється можливим в хромі, посилання: stackoverflow.com/questions/37782104 / ...
Abhijeet

Відповіді:


300

Ви не можете змінити діалог за замовчуванням для onbeforeunload, так що найкраще може працювати з ним.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Ось посилання на це від Microsoft:

Коли рядок присвоєно властивість returnValue window.event, з'явиться діалогове вікно, яке дає користувачам можливість залишитися на поточній сторінці та зберегти рядок, який їй був призначений. Заява за замовчуванням, що з'являється у діалоговому вікні "Ви впевнені, що хочете перейти з цієї сторінки? ... Натисніть OK, щоб продовжити, або Скасувати, щоб залишитися на поточній сторінці", не можна видалити або змінити.

Здається, проблема:

  1. Коли onbeforeunloadбуде викликано, воно буде приймати повернене значення обробника як window.event.returnValue.
  2. Потім воно буде аналізувати повернене значення у вигляді рядка (якщо воно не є нульовим).
  3. Оскільки falseпроаналізовано як рядок, діалогове вікно запуститься, яке потім передасть відповідне true/ false.

Результат, як видається , же не бути способом призначення falseдля onbeforeunloadзапобігання його від діалогу за замовчуванням.

Додаткові примітки до jQuery:

  • Встановлення події в jQuery може бути проблематичним, оскільки це дозволяє onbeforeunloadтакож відбуватися й інші події. Якщо ви хочете, щоб відбулася ваша подія розвантаження, я б дотримувався звичайного ol 'JavaScript для цього.
  • jQuery не має ярлика, onbeforeunloadтому вам доведеться використовувати загальний bindсинтаксис.

    $(window).bind('beforeunload', function() {} );

Редагувати 09.04.2018 : користувацькі повідомлення в діалогових вікнах перед завантаженням застаріли з часу chrome-51 (див .: примітка до випуску )


20
Я виявив, що приклад JQuery, наведений наприкінці, не працює у firefox. Дотримуйтесь простого способу: window.onbeforeunload = function () {...}
jb.

21
Лише зауважте, що Firefox нещодавно було змінено так, що текст у діалоговому вікні неможливо навіть налаштувати: bugzilla.mozilla.org/show_bug.cgi?id=588292
Девід Хаммонд

15
Але як тоді Facebook надає спеціальне діалогове вікно? наприклад, перейдіть на сторінку повідомлень, відповідайте на повідомлення свого друга, а потім, перш ніж натиснути надіслати, спробуйте клацнути інше посилання. ви побачите користувальницьке діалогове вікно
Varun

20
@Varun - старі новини, але Facebook, можливо, ставить обробників на події натискання всіх своїх якорів, але якщо ви перезаписуєте URL-адресу в браузер або закриєте вікно, він повертається до стандартного методу, над яким вони не мають контролю.
Tabloo Quijico

1
@Varun Я також здивований, що ця відповідь, яка не дає можливості, позначається як відповідь і має 150 підказок ... Щойно зрозуміло, що власні повідомлення FB доступні лише за посиланнями на їхньому сайті. Якщо не просто перейти геть ...
Sébastien Richer

28

Що для мене працювало, використовуючи jQuery та перевірені в IE8, Chrome та Firefox, це:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

Важливо не повертати нічого, якщо не потрібно запитувати, оскільки тут є відмінності між IE та іншою поведінкою браузера.


Цікаво, що event.returnValueце єдиний «затверджений» метод в IE. IE продовжує говорити: "Значення цього властивості має перевагу над значеннями, поверненими функцією, наприклад, через оператор повернення Microsoft JScript". .. було б добре побачити гарантовану кореляцію між return(від події) та event.returnValue..

21

Хоча ви не можете зробити щось із цього поля за певних обставин, ви можете перехопити когось, хто натисне посилання. Для мене це було вартим зусиль для більшості сценаріїв, і як резерв я покинув подію вивантаження.

Я використовував Boxy замість стандартного діалогу jQuery, він доступний тут: http://onehackoraTHER.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

Ви можете приєднатись до іншої події та більше фільтрувати, на який саме тип якоря натискали, але це працює для мене, і що я хочу зробити, і слугує прикладом для інших чи використання. Думав, я поділюсь цим для тих, хто хоче цього рішення.

Я вирізав код, тому це може не працювати так, як є.


return "Ви внесли деякі зміни, які ви хочете зберегти." не працював для мене. Мені довелося зберігати повідомлення у змінній мові "попереджувальний_місаж", і я повернув попереджувальний_місаж. Тоді тільки на мене це працювало !.
Suganya

ви протестували в IE, Chrome, Firefox?
Кікенет

9

1) Використовуйте для попереднього завантаження, а не для завантаження.

2) Важливим є уникати виконання декларації про повернення. Я не маю на увазі, щоб уникнути повернення з вашого обробника. Ви повертаєте все в порядку, але це робите, гарантуючи, що ви досягнете кінця функції і НЕ виконуєте оператор повернення. За цих умов вбудований стандартний діалог не відбувається.

3) Якщо ви можете використовувати onbeforeunload, ви можете запустити виклик ajax у вашому оброблювальному пристрої для попереднього завантаження, щоб привести в порядок сервер, але він повинен бути синхронним. стан (2) вище). Я це роблю, і це прекрасно працює. Якщо ви робите синхронний ajax-дзвінок, все тримається, поки відповідь не повернеться. Якщо ви робите асинхронний, думаючи, що вам не байдужий відповідь з сервера, розвантаження сторінки триває і ваш виклик Ajax припиняється цим процесом - включаючи віддалений скрипт, якщо він працює.


Просто FYI, хто читає це ^ Хром знецінює синхронні дзвінки AJAX у неперевантаженому режимі
morganwebdev

4

Спробуйте розмістити return;замість повідомлення .. це працює для більшості браузерів. (Це дійсно запобігає подарункам діалогу)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}

3
return null запобіжить відкриттю діалогу
Бретт Вебер

1
return null НЕ перешкоджає відкриттю діалогу. Я спробував це в Chrome, і це не так.
Рей

2
Я можу підтвердити коментар Рея в IE. Повернення nullвідкриє діалогове вікно з текстом "null". Однак return void(0);діалогове вікно не відкриється.
MCattle

1
Якщо не вставити будь-яку операцію повернення всередину функції перед завантаженням, діалогове вікно не відкриється.
OuuGiii


3

Ви можете визначити, яку кнопку (ok чи скасувати) натиснув користувач, оскільки функція завантаження викликається лише тоді, коли користувач вирішує залишити сторінку. У цьому функціонуванні всі можливості обмежені, оскільки DOM руйнується. Ви можете запускати javascript, але ajax POST нічого не робить, тому ви не можете використовувати цей метод для автоматичного виходу. Але для цього є рішення. Window.open ('logout.php') виконується під час завантаження, тому користувач вийде з нового відкриття вікна.

function onunload = (){
    window.open('logout.php');
}

Цей код викликається, коли користувач залишає сторінку або закриває активне вікно та користувач виходить із системи „logout.php“. Нове вікно негайно закриється, коли PHP виходу складається з коду:

window.close();

Ви можете використовувати синхронний пост у функціях передзавантаження та вивантаження. Особливо, якщо вам потрібні дані назад із сервера. Будь-який код асинхронізації в цих блоках може не завершитися до моменту завантаження сторінки.
jemiloii

3

Я зіткнувся з тією ж проблемою, я був у порядку, щоб отримати своє власне діалогове вікно зі своїм повідомленням, але проблема, з якою я зіткнулася, полягала в наступному: 1) Це повідомлення було передано на всіх навігаціях, я хочу його лише для близького клацання. 2) з моїм власним повідомленням про підтвердження, якщо користувач вибирає скасувати, воно все ще показує діалогове вікно браузера за замовчуванням.

Далі йде код знайденого рішення, який я написав на своїй сторінці Майстер.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;


1

Як щодо використання спеціалізованої версії команди "bind" "one". Як тільки обробник подій виконується вперше, він автоматично видаляється як обробник подій.

$(window).one("beforeunload", BeforeUnload);

досить впевнений, що це .on ("beforeunload"
Сергіу Міндрас

2
@SergiuMindras ні, це .one()- те, що приєднує слухача події слухати, щоб подія відбулася лише один раз: "Приєднайте обробник до події для елементів. Обробник виконується не більше одного разу на елемент для кожного типу події." api.jquery.com/one
Шон Кендл

0

Кутовий 9 підхід:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Підтримка веб-переглядачів та видалення користувацького повідомлення:

  • Chrome видалила підтримку користувацького повідомлення через версію 51 хв
  • Opera видалила підтримку користувацького повідомлення через версію 38 хв
  • Firefox видалив підтримку користувацького повідомлення через версію 44.0 хв
  • Safari видалив підтримку користувацького повідомлення у версії 9.1 хв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.