Làm cách nào tôi có thể ghi đè hộp thoại OnB BeforeUnload và thay thế nó bằng hộp thoại của riêng tôi?


346

Tôi cần cảnh báo người dùng về những thay đổi chưa được lưu trước khi họ rời khỏi một trang (một vấn đề khá phổ biến).

window.onbeforeunload=handler

Điều này hoạt động nhưng nó làm tăng một hộp thoại mặc định với một thông điệp tiêu chuẩn gây khó chịu bao bọc văn bản của riêng tôi. Tôi cần phải thay thế hoàn toàn thông điệp tiêu chuẩn, để văn bản của tôi rõ ràng hoặc (thậm chí tốt hơn) thay thế toàn bộ hộp thoại bằng hộp thoại phương thức bằng jQuery.

Cho đến nay tôi đã thất bại và tôi không tìm thấy ai khác dường như có câu trả lời. Nó thậm chí có thể?

Javascript trong trang của tôi:

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

Hàm closeIt ():

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

Sử dụng jQuery và jqModal Tôi đã thử loại điều này (sử dụng hộp thoại xác nhận tùy chỉnh):

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

mà cũng không hoạt động - tôi dường như không thể liên kết với sự kiện trước khi tải.


1
bạn có thể đưa ra một ví dụ về mã hiện tại của bạn và những gì nó tạo ra?
Owen

Owen đã đúng. Và, lý do đằng sau điều này là bảo mật. Ngăn chặn một trang tải xuống là hữu ích trong các hình thức web và như vậy, nhưng nó có thể dễ dàng bị khai thác bởi một trang web độc hại để đánh lừa người dùng ở lại trên một trang. Đó là lý do tại sao trình duyệt web triển khai thông báo chuẩn và có cơ chế này để chèn văn bản tùy chỉnh.
pluckyglen

xem tại đây để biết thêm thông tin: stackoverflow.com/questions/140460
Ben McIntyre


1
không thể có trong chrome, tham khảo: stackoverflow.com/questions/37782104/ từ
Abhijeet

Câu trả lời:


299

Bạn không thể sửa đổi đối thoại mặc định cho onbeforeunload, vì vậy đặt cược tốt nhất của bạn có thể là làm việc với nó.

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

Đây là một tài liệu tham khảo từ Microsoft:

Khi một chuỗi được gán cho thuộc tính returnValue của window.event, một hộp thoại xuất hiện cung cấp cho người dùng tùy chọn ở lại trang hiện tại và giữ lại chuỗi được gán cho nó. Câu lệnh mặc định xuất hiện trong hộp thoại, "Bạn có chắc chắn muốn điều hướng khỏi trang này không? ... Nhấn OK để tiếp tục hoặc Hủy để ở lại trang hiện tại.", Không thể xóa hoặc thay đổi.

Vấn đề dường như là:

  1. Khi onbeforeunloadđược gọi, nó sẽ lấy giá trị trả về của trình xử lý là window.event.returnValue.
  2. Sau đó, nó sẽ phân tích giá trị trả về dưới dạng một chuỗi (trừ khi nó là null).
  3. falseđược phân tích cú pháp dưới dạng chuỗi, hộp thoại sẽ kích hoạt, sau đó sẽ truyền true/ thích hợp false.

Kết quả là, có vẻ không phải là một cách gán falsetới onbeforeunloadđể ngăn chặn nó từ đối thoại mặc định.

Ghi chú bổ sung trên jQuery:

  • Việc đặt sự kiện trong jQuery có thể có vấn đề, vì điều đó cũng cho phép các onbeforeunloadsự kiện khác xảy ra. Nếu bạn chỉ muốn sự kiện dỡ tải của mình xảy ra, tôi sẽ sử dụng JavaScript đơn giản cho nó.
  • jQuery không có lối tắt onbeforeunloadđể bạn phải sử dụng bindcú pháp chung .

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

Chỉnh sửa 09/04/2018 : tin nhắn tùy chỉnh trong hộp thoại onb Beforeunload không được dùng nữa kể từ chrome-51 (cf: ghi chú phát hành )


20
Tôi đã thấy rằng ví dụ JQuery đưa ra ở cuối không hoạt động trong firefox. Thay vào đó, hãy sử dụng cách đơn giản: window.onb Beforeunload = function () {...}
jb.

21
Chỉ cần lưu ý rằng Firefox gần đây đã được thay đổi để văn bản trong hộp thoại thậm chí không thể được tùy chỉnh: bugzilla.mozilla.org/show_orms.cgi?id=588292
David Hammond

15
Nhưng làm thế nào để facebook cung cấp một hộp thoại tùy chỉnh sau đó? ví dụ: truy cập trang tin nhắn, trả lời tin nhắn của bạn bè và sau đó trước khi nhấp gửi, hãy thử nhấp vào liên kết khác. bạn sẽ thấy một cửa sổ bật lên hộp thoại tùy chỉnh
Varun

20
@Varun - Tin tức cũ nhưng Facebook có thể đưa trình xử lý vào sự kiện nhấp chuột của tất cả các neo của họ, nhưng nếu bạn viết lại URL trong trình duyệt hoặc đóng cửa sổ, nó sẽ trở lại phương thức chuẩn mà họ không kiểm soát được.
Tabloo Quijico

1
@Varun Tôi cũng ngạc nhiên khi câu trả lời này không thể đánh dấu là câu trả lời và có 150 câu trả lời ... Chỉ cần nhận ra, thông điệp tùy chỉnh của FB chỉ có sẵn thông qua các liên kết bên trong trang web của họ. Không phải nếu bạn chỉ đơn giản là điều hướng đi ...
Sébastien Richer

28

Điều làm việc cho tôi, sử dụng jQuery và được thử nghiệm trong IE8, Chrome và Firefox, là:

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

Điều quan trọng là không trả lại bất cứ điều gì nếu không có yêu cầu nhắc nhở vì có sự khác biệt giữa IE và các hành vi trình duyệt khác ở đây.


Thật thú vị, event.returnValuelà phương pháp "được phê duyệt" duy nhất trong IE. IE tiếp tục nói "Giá trị của thuộc tính này được ưu tiên hơn các giá trị được trả về bởi hàm, chẳng hạn như thông qua câu lệnh trả về Microsoft JScript." .. thật tuyệt khi thấy mối tương quan được đảm bảo giữa return(từ sự kiện) và event.returnValue..

21

Mặc dù không có bất cứ điều gì bạn có thể làm về hộp trong một số trường hợp, bạn có thể chặn ai đó nhấp vào liên kết. Đối với tôi, điều này đáng để nỗ lực cho hầu hết các kịch bản và như một dự phòng, tôi đã rời khỏi sự kiện dỡ hàng.

Tôi đã sử dụng Boxy thay vì Hộp thoại jQuery tiêu chuẩn, nó có sẵn ở đây: http://onehackoranother.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.';
    }
};

Bạn có thể đính kèm vào một sự kiện khác và lọc thêm về loại neo nào được nhấp, nhưng điều này hiệu quả với tôi và những gì tôi muốn làm và làm ví dụ cho những người khác sử dụng hoặc cải thiện. Nghĩ rằng tôi sẽ chia sẻ điều này cho những người muốn giải pháp này.

Tôi đã cắt bỏ mã, vì vậy điều này có thể không hoạt động như là.


trở lại 'Bạn đã thực hiện một số thay đổi mà bạn có thể muốn lưu.' đã không làm việc cho tôi. Tôi đã phải lưu trữ tin nhắn trong một biến có nội dung 'warning_message' và tôi đã trả lại cảnh báo_message. Sau đó, chỉ có nó làm việc cho tôi!.
Suganya

bạn đã thử nghiệm trên IE, Chrome, Firefox chưa?
Kiquenet

9

1) Sử dụng onb Beforeunload, không onunload.

2) Điều quan trọng là tránh thực hiện một tuyên bố trả lại. Tôi không có ý, bằng cách này, để tránh trở về từ xử lý của bạn. Bạn trả lại đúng, nhưng bạn làm điều đó bằng cách đảm bảo rằng bạn đạt đến cuối hàm và KHÔNG thực hiện câu lệnh return. Trong các điều kiện này, hộp thoại tiêu chuẩn tích hợp không xảy ra.

3) Bạn có thể, nếu bạn sử dụng onb Beforeunload, hãy chạy một cuộc gọi ajax trong trình xử lý unb Beforeunload của bạn để dọn dẹp trên máy chủ, nhưng nó phải là một cuộc gọi đồng bộ, và bạn phải chờ và xử lý trả lời trong trình xử lý onb Beforeunload của bạn (vẫn tôn trọng điều kiện (2) ở trên). Tôi làm điều này và nó hoạt động tốt. Nếu bạn thực hiện cuộc gọi ajax đồng bộ, mọi thứ sẽ được duy trì cho đến khi phản hồi trở lại. Nếu bạn thực hiện một cách không đồng bộ, nghĩ rằng bạn không quan tâm đến câu trả lời từ máy chủ, việc hủy tải trang sẽ tiếp tục và cuộc gọi ajax của bạn bị hủy bỏ bởi quy trình này - bao gồm cả tập lệnh từ xa nếu nó đang chạy.


Chỉ cần FYI bất cứ ai đọc điều này ^ Chrome đang từ chối các cuộc gọi AJAX đồng bộ trong unb Beforeunload
morganwebdev

4

Hãy thử đặt một return;thay vì một tin nhắn .. điều này đang làm việc với hầu hết các trình duyệt đối với tôi. (Điều này chỉ thực sự ngăn chặn quà tặng của hộp thoại)

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

3
return null sẽ ngăn hộp thoại mở
Brett Weber

1
return null sẽ KHÔNG ngăn hộp thoại mở. Tôi đã thử nó trong Chrome và không phải vậy.
Ray

2
Tôi cũng có thể xác nhận nhận xét của Ray trong IE. Trở về nullsẽ mở một hộp thoại với văn bản "null". Tuy nhiên, return void(0);sẽ không mở hộp thoại.
MCattle

1
Bằng cách không đặt bất kỳ câu lệnh return nào bên trong hàm beforeunload, hộp thoại sẽ không mở.
OuuGiii


3

Bạn có thể phát hiện nút nào (ok hoặc hủy) được nhấn bởi người dùng, bởi vì chức năng onunload chỉ được gọi khi người dùng chọn rời khỏi trang. Althoug trong chức năng này khả năng bị hạn chế, vì DOM đang bị sụp đổ. Bạn có thể chạy javascript, nhưng ajax POST không làm gì cả do đó bạn không thể sử dụng phương thức này để đăng xuất tự động. Nhưng có một giải pháp cho điều đó. Window.open ('logout.php') được thực thi trong chức năng onunload, vì vậy người dùng sẽ đăng xuất với một cửa sổ mới mở.

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

Mã này được gọi khi người dùng rời khỏi trang hoặc đóng cửa sổ đang hoạt động và người dùng đăng xuất bằng 'logout.php'. Cửa sổ mới đóng ngay lập tức khi đăng xuất php bao gồm mã:

window.close();

Bạn có thể sử dụng một bài đăng đồng bộ trong các chức năng trước khi tải và dỡ tải. Đặc biệt nếu bạn cần dữ liệu trở lại từ máy chủ. Bất kỳ mã async nào trong các khối đó có thể không được hoàn thành trước thời điểm trang tải xuống.
jemiloii

3

Tôi đã đối mặt với cùng một vấn đề, tôi vẫn ổn khi nhận được hộp thoại của riêng mình với tin nhắn của mình, nhưng vấn đề tôi gặp phải là: 1) Nó đã đưa ra thông điệp trên tất cả các điều hướng mà tôi muốn chỉ khi nhấp gần. 2) với thông báo xác nhận của riêng tôi nếu người dùng chọn hủy, nó vẫn hiển thị hộp thoại mặc định của trình duyệt.

Sau đây là mã giải pháp tôi tìm thấy, mà tôi đã viết trên trang Master của mình.

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
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

tham khảo từ http://www.codeprojectdoad.com


1

Điều gì về việc sử dụng phiên bản chuyên biệt của lệnh "liên kết" "một". Khi trình xử lý sự kiện thực thi lần đầu tiên, nó sẽ tự động bị xóa như một trình xử lý sự kiện.

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

khá chắc chắn đây là .on ("beforeunload"
Sergiu Mindras

2
@SergiuMindras không, đó là .one()- nó gắn một người nghe sự kiện để lắng nghe sự kiện chỉ xảy ra một lần: "Đính kèm một trình xử lý cho một sự kiện cho các phần tử. Trình xử lý được thực thi nhiều nhất một lần cho mỗi phần tử cho mỗi loại sự kiện." api.jquery.com/one
Sean Kendle

0

Cách tiếp cận góc 9:

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

Trình duyệt hỗ trợ và loại bỏ thông báo tùy chỉnh:

  • Chrome đã xóa hỗ trợ cho thông báo tùy chỉnh trong ver 51 phút
  • Opera loại bỏ hỗ trợ cho thông điệp tùy chỉnh trong ver 38 phút
  • Firefox đã loại bỏ hỗ trợ cho thông báo tùy chỉnh trong ver 44.0 phút
  • Safari đã xóa hỗ trợ cho thông báo tùy chỉnh trong ver 9.1 min
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.