如何在提交更改时显示“您确定要离开此页面吗?”

315

在stackoverflow中,如果你开始进行更改并尝试离开页面,会出现一个JavaScript确认按钮询问:“确定要离开此页面吗?”仿佛如闻其声...

有人实现过这个功能吗?我该怎么追踪提交的更改?我相信我可以自己完成,我正在尝试从专家那里学习好的做法。

我尝试了以下方法,但仍然无效:

<html>
<body>
    <p>Close the page to trigger the onunload event.</p>
    <script type="text/javascript">
        var changes = false;        
        window.onbeforeunload = function() {
            if (changes)
            {
                var message = "Are you sure you want to navigate away from this page?\n\nYou have started writing or editing a post.\n\nPress OK to continue or Cancel to stay on the current page.";
                if (confirm(message)) return true;
                else return false;
            }
        }
    </script>

    <input type='text' onchange='changes=true;'> </input>
</body>
</html>

有人可以提供一个例子吗?


3
为让您的示例正常工作,请更改函数为:myFunction() { window.onbeforeunload = "message"; },然后更改输入:<input type='text' onchange='myFunction();'></input>。 - Keith
相关链接:https://dev59.com/N3RA5IYBdhLWcg3wzhRY - AlikElzin-kilaka
17个回答

454

更新(2017年)

现代浏览器现在认为显示自定义消息是一种安全隐患,因此已经从所有浏览器中移除。现在浏览器只显示通用消息。由于我们不再需要担心设置消息,所以它变得非常简单:

// Enable navigation prompt
window.onbeforeunload = function() {
    return true;
};
// Remove navigation prompt
window.onbeforeunload = null;

阅读以下内容以获取旧版浏览器支持。

更新(2013年)

原始答案适用于IE6-8和FX1-3.5(这是我们在编写它时所针对的),但现在已经过时,在大多数当前浏览器中不起作用- 我已经将其保留供参考。

window.onbeforeunload 在所有浏览器中的处理方式并不一致。它应该是一个函数引用而不是字符串(正如原始答案所述),但在旧版浏览器中,这也可以工作,因为对于大多数浏览器来说,检查是否分配了任何内容都会被视为onbeforeunload(包括返回null的函数)。

您将 window.onbeforeunload 设置为函数引用,但在旧版浏览器中,您必须设置事件的 returnValue 而不仅仅返回一个字符串:

var confirmOnPageExit = function (e) 
{
    // If we haven't been passed the event get the window.event
    e = e || window.event;

    var message = 'Any text will block the navigation and display a prompt';

    // For IE6-8 and Firefox prior to version 4
    if (e) 
    {
        e.returnValue = message;
    }

    // For Chrome, Safari, IE8+ and Opera 12+
    return message;
};

你不能让 confirmOnPageExit 做检查,如果你希望用户在没有提示消息的情况下继续操作则返回 null。你仍然需要移除事件以可靠地打开和关闭它:
// Turn it on - assign the function that returns the string
window.onbeforeunload = confirmOnPageExit;

// Turn it off - remove the function entirely
window.onbeforeunload = null;

原始答案(适用于2009年)

打开它的方法:

window.onbeforeunload = "Are you sure you want to leave?";

关闭它:

window.onbeforeunload = null;

请记住这不是一个常规事件 - 你不能以标准方式绑定它。
检查值?这取决于您的验证框架。
在 jQuery 中,可以像下面这样实现(非常基本的例子):
$('input').change(function() {
    if( $(this).val() != "" )
        window.onbeforeunload = "Are you sure you want to leave?";
});

4
这段代码大致意思是:当文本输入框的内容改变时,判断是否有非空文本框,如果有则弹出提示信息“warning”,否则不作任何操作。具体的实现方式是通过jQuery监听文本框的change事件,并在回调函数中根据文本框的值来设置window.onbeforeunload属性的值。 - Keith
1
对于简单的检查,或者您可以在每次更改时添加更复杂的验证。 - Keith
1
值得注意的是,'returnValue'方法是标准中唯一指定的方法,因此它不仅适用于IE6-8,而且适用于所有符合标准的浏览器(在这种情况下不包括Chrome、Safari和Opera)。 - rmcclellan
3
为了在表单提交时停止警报,我使用了 $("#submit_button").click(function() { window.onbeforeunload = null; });。我最初使用了按钮的 onclick 事件,但它不仅不够好,而且在 IE8 中也无法正常工作。 - Andy Beverley
1
@AlikElzin-kilaka 你不能这样做。如果你想要改变弹出文本,那么你需要创建自己的自定义弹出窗口,但是它无法阻止 window.onbeforeunload 事件。 - Keith
显示剩余17条评论

41

onbeforeunload是最接近标准解决方案的Microsoft-ism,但请注意浏览器支持度不一致;例如,对于Opera只在版本12及更高版本(截至本文写作时仍处于测试版)中可用。

此外,为了实现最大兼容性,您需要执行更多操作,详见Mozilla开发者网络的说明。

示例:定义以下两个函数以启用/禁用导航提示(参见MDN示例):

function enableBeforeUnload() {
    window.onbeforeunload = function (e) {
        return "Discard changes?";
    };
}
function disableBeforeUnload() {
    window.onbeforeunload = null;
}

那么就定义一个像这样的表单:

<form method="POST" action="" onsubmit="disableBeforeUnload();">
    <textarea name="text"
              onchange="enableBeforeUnload();"
              onkeyup="enableBeforeUnload();">
    </textarea>
    <button type="submit">Save</button>
</form>

这样,只有当用户更改了文本区域时,才会警告用户离开页面,而在实际提交表单时不会提示。


1
根据Mozilla网站,大多数最新的桌面浏览器现在都支持它:https://developer.mozilla.org/en/DOM/window.onbeforeunload - Hengjie
Microsoft-ism是一个很棒的术语。 - Luke Taylor

20

18

使用JQuery这件事情非常容易。因为你可以绑定到一组元素。

仅仅使用onbeforeunload是不够的,如果有人开始编辑内容,你希望只触发导航离开事件。


2
似乎无法找到@jonstjohn的博客文章。也许他会帮我们指明方向?:D - FLGMwt
16
500内部错误。这就是为什么在SO上链接已经被废弃的原因。直到修复之前投票反对。 - Loïc
该网页无法访问。 - Mateusz
3
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分,并提供链接作为参考。仅有链接的答案如果链接页面发生更改可能会变得无效。 - bwest
2009年@bwest,随意编辑此答案,我写了这个答案已经很久了。 - Sam Saffron
2
原本的Jon St John链接已经失效,所以我更新了它到Wayback Machine版本(http://web.archive.org/web/20130730025134/http://jonstjohn.com/node/23)。这个链接的内容可以在许多其他网站上找到副本,但我认为保留Sam添加的那个更好。 - Alvaro Montoro

14

jQuery的'beforeunload'对我非常有用。

$(window).bind('beforeunload', function(){
    if( $('input').val() !== '' ){
        return "It looks like you have input you haven't submitted."
    }
});

Bind已被淘汰,类似于这个答案中所示的新版本代码:https://dev59.com/ZHI-5IYBdhLWcg3wYXL8#1889450 - Elijah Lofgren

11
这是一种简单的方式,如果表单中输入了任何数据,则呈现消息,如果提交表单,则不显示该消息:
$(function () {
    $("input, textarea, select").on("input change", function() {
        window.onbeforeunload = window.onbeforeunload || function (e) {
            return "You have unsaved changes.  Do you want to leave this page and lose your changes?";
        };
    });
    $("form").on("submit", function() {
        window.onbeforeunload = null;
    });
})

8

Keith 的精彩回答 的基础上进行拓展:

自定义警告信息

为了允许自定义警告信息,您可以像这样将其包装在一个函数中:

function preventNavigation(message) {
    var confirmOnPageExit = function (e) {
        // If we haven't been passed the event get the window.event
        e = e || window.event;

        // For IE6-8 and Firefox prior to version 4
        if (e)
        {
            e.returnValue = message;
        }

        // For Chrome, Safari, IE8+ and Opera 12+
        return message;
    };
    window.onbeforeunload = confirmOnPageExit;
}

那么只需使用您自己的信息调用该函数即可:
preventNavigation("Baby, please don't go!!!");

重新启用导航

要重新启用导航,您只需要将window.onbeforeunload设置为null即可。这是一个简洁的小函数,可在任何地方调用:

function enableNavigation() {
    window.onbeforeunload = null;
}

使用jQuery绑定表单元素的this

如果使用jQuery,可以轻松地将this绑定到表单的所有元素上,代码如下:

$("#yourForm :input").change(function() {
    preventNavigation("You have not saved the form. Any \
        changes will be lost if you leave this page.");
});

然后允许表单提交:
$("#yourForm").on("submit", function(event) {
    enableNavigation();
});

动态修改的表单:

preventNavigation()enableNavigation()可以绑定到其他需要的函数,比如动态修改表单或点击发送AJAX请求的按钮。这可以通过向表单添加隐藏的输入元素来实现:

<input id="dummy_input" type="hidden" />

当我想要防止用户离开页面时,我会触发该输入框的更改以确保执行preventNavigation()

function somethingThatModifiesAFormDynamically() {

    // Do something that modifies a form

    // ...
    $("#dummy_input").trigger("change");
    // ...
}

5

标准规定,提示可以通过取消beforeunload事件或将返回值设置为非空值来进行控制。它还指出作者应该使用Event.preventDefault()替代returnValue,并且向用户显示的消息无法自定义

截至69.0.3497.92版本,Chrome尚未达到标准。但是已经有错误报告提交,并且正在进行审核。Chrome要求通过引用事件对象而不是处理程序返回的值来设置returnValue。

作者有责任跟踪是否已经进行了更改;可以通过变量或确保仅在必要时处理事件来完成。

window.addEventListener('beforeunload', function (e) {
    // Cancel the event as stated by the standard.
    e.preventDefault();
    // Chrome requires returnValue to be set.
    e.returnValue = '';
});
    
window.location = 'about:blank';


3

试试这个,它百分百有效。

<html>
<body>
<script>
var warning = true;
window.onbeforeunload = function() {  
  if (warning) {  
    return "You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes";  
    }  
}

$('form').submit(function() {
   window.onbeforeunload = null;
});
</script>
</body>
</html>

3
当用户开始更改表单时,将设置一个布尔标志。如果用户尝试离开页面,则在window.onunload事件中检查该标志。如果设置了标志,则通过将其作为字符串返回来显示消息。将消息作为字符串返回将弹出包含您的消息的确认对话框。
如果您正在使用ajax提交更改,则可以在更改已被提交后(即在ajax成功事件中)将标志设置为false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接