如何确定用户在JavaScript的onbeforeunload对话框中单击了“取消”?

36

当有人尝试离开某个页面而没有保存他们的工作时,我会弹出一个对话框。我使用JavaScript的onbeforeunload事件,效果很好。

现在我想在用户单击对话框上的“取消”按钮时运行一些JavaScript代码(表示他们不想离开该页面)。

这种做法可行吗?我也使用jQuery,所以是否可以绑定类似于beforeunloadcancel的事件呢?

更新:实际上,这个想法是在选择取消时保存并将用户引导到另一个网页。


我不认为这是可能的......但我希望我错了。 - keithjgrant
我非常好奇如何使用自定义对话框来阻止导航器。你能提供代码吗? - jAndy
@jAndy,查找一下JavaScript中的onbeforeunload事件,它恰好可以实现这个功能。 - at.
@at: 我知道这个事件,但它只适用于弹出的默认模式对话框。你的帖子听起来像是在事件处理程序内创建自定义UI对话框或其他东西。 - jAndy
6个回答

62

你可以这样做:

$(function() {
    $(window).bind('beforeunload', function() {
        setTimeout(function() {
            setTimeout(function() {
                $(document.body).css('background-color', 'red');
            }, 1000);
        },1);
        return 'are you sure';
    });
}); 

第一个 setTimeout 方法中的代码延迟1毫秒。这只是为了将函数添加到 UI队列 中。由于 setTimeout 异步运行,JavaScript解释器将通过直接调用 return 语句继续执行,从而触发浏览器的 模态对话框。这将阻塞 UI队列 并且来自第一个 setTimeout 的代码不会被执行,直到模态框关闭。如果用户取消了操作,则会触发另一个 setTimeout,大约1秒后触发。如果用户确认并点击 ok,则用户将被重定向,第二个 setTimeout 将永远不会触发。

示例:http://www.jsfiddle.net/NdyGJ/2/


1
@jAndy。当用户选择“离开此页面”选项时,SetTimeOut也会触发。我们如何停止这个行为? - VIJAY
3
截至2014年1月,在Chrome浏览器上这种方法不起作用。 - Scott Evernden
1
@ScottEvernden 我刚刚用两个最近的Chrome版本测试了一下,它可以正常工作(再次?),包括40.0.2214.94版本。 - timing
2
在网络连接较慢的情况下,此方法无效:第二个超时函数会在确认选择之前被调用,并且可能会在实际卸载之前执行(在被限制的Chrome浏览器中)。 - Sjeiti
1
实际页面卸载时间取决于开始获取下一页所需的时间。如果用户的电脑速度较慢,或者下一页的服务器响应缓慢,则此方法将错误地判断用户已取消离开。它极其不可靠。 - Vsevolod Golovanov
显示剩余10条评论

6

我知道这个问题现在已经老了,但是如果还有人遇到这个问题,我找到了一个似乎对我有效的解决方案。

基本上,在 beforeunload 事件之后会触发 unload 事件。我们可以利用这一点来取消在 beforeunload 事件中创建的超时,修改jAndy的答案:

$(function() {
    var beforeUnloadTimeout = 0 ;
    $(window).bind('beforeunload', function()  {
        console.log('beforeunload');
        beforeUnloadTimeout = setTimeout(function() {
            console.log('settimeout function');
            $(document.body).css('background-color', 'red');
        },500);
        return 'are you sure';
    });
    $(window).bind('unload', function() {
        console.log('unload');
        if(typeof beforeUnloadTimeout !=='undefined' && beforeUnloadTimeout != 0)
            clearTimeout(beforeUnloadTimeout);
    });
}); 

EDIT: jsfiddle here


这对你有用吗?因为在我的情况下,计时器函数执行后很长时间才会出现“unload”...(我在Firefox 35中进行了测试) - Alexis Wilke
是的,这对我有效,请尝试增加超时函数的时间。 - 99 Problems - Syntax ain't one
我进行了更多的测试,发现如果我设置大约5秒钟(而不是0.5秒),它会按预期工作。但是,如果您取消对话框,我认为那太长了...很遗憾我们在这方面没有得到更好的反馈。 - Alexis Wilke
这是一个很好的想法。但是,它受延迟影响。在最坏的情况下,Web 服务器被关闭,beforeunload 超时的长度必须等于浏览器的超时时间。 - Trevor Karjanis

2

我之前觉得这是不可能的,但我试了一下这个想法,它可以运行(虽然有点像黑客技巧,在所有浏览器中可能不会起作用):

window.onbeforeunload = function () {   
  $('body').mousemove(checkunload);
  return "Sure thing"; 
};

function checkunload() {   
  $('body').unbind("mousemove");
  //ADD CODE TO RUN IF CANCEL WAS CLICKED
}

2
如果您在单击“确定”离开网站后移动鼠标,则“取消代码”仍将运行... - at.
我猜你可以在绑定mousemove事件之前添加一个超时,这可能会修复它,尽管这使它更像是一个hack。 - Barlow Tucker
2
现有窗口消失需要超过1秒的时间,如果在此期间移动鼠标,则会看起来像是取消操作。使用计时器与jAndy的答案存在相同的缺点,对我来说并不适用。 - Alexis Wilke

2

不可能的。也许有人会证明我错了...你想运行什么代码?当用户点击取消时,你想自动保存吗?这听起来很反直觉。如果你还没有自动保存,我认为在他们点击“取消”时自动保存是没有意义的。也许你可以在onbeforeunload处理程序中突出显示保存按钮,以便用户在导航离开之前看到他们需要做什么。


这个想法是,如果用户选择取消,实际上将保存并引导他们到另一个网页。 - at.

0

另一种变化 第一个 setTimeout 等待用户响应浏览器的“离开/取消”弹出窗口。第二个 setTimeout 等待 1 秒,然后仅在用户取消时调用 CancelSelected。否则页面将被卸载并且 setTimeout 将会失效。

window.onbeforeunload  = function(e) {
    e.returnValue = "message to user";
    setTimeout(function () { setTimeout(CancelSelected, 1000); }, 100);
}

function CancelSelected() {
    alert("User selected stay/cancel");
}

如果我刷新页面并选择退出,新页面需要一些时间才能加载,那么警报会显示...不好。 - Gonçalo Gaspar

-7
window.onbeforeunload  = function() {
    if (confirm('Do you want to navigate away from this page?')) {
        alert('Saving work...(OK clicked)')
    } else {
        alert('Saving work...(canceled clicked)')
        return false
    }
 }

通过这段代码,即使用户在IE8中单击“取消”,默认的导航对话框也会出现。


3
你不能在附加到 onbeforeunload 的函数中使用 confirm() - Alexis Wilke
@jyoti:看起来你想评论别人的答案。要这样做,请单击具体答案下面的“添加评论”链接。请从主题中删除此答案,因为现在它是一个错误答案的重复,否则很快就会被投票降低评分。 - Oliver

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