代码之家  ›  专栏  ›  技术社区  ›  David Murdoch

window.onbeforeunload可能会触发多次

  •  9
  • David Murdoch  · 技术社区  · 14 年前

    仅仅因为你看不到对某个功能的使用并不意味着它没有用处。

    堆栈交换网络,Gmail,grooveshark,雅虎!邮件和hotmail使用onbeforeunload提示来防止/警告用户在开始编辑某个页面后离开该页面。哦,是的, 几乎每个桌面程序 它接受可保存的用户输入数据,在离开UX模式之前使用这个提示用户。


    我有一个类似于这个的函数:

    window.onbeforeunload = function(){
        // only prompt if the flag has been set... 
        if(promptBeforeLeaving === true){
            return "Are you sure you want to leave this page?";
        }
    }
    

    当用户试图离开页面时,浏览器会向他们显示离开或停留在页面上的选项。如果用户选择“离开此页面选项”,然后在页面完全卸载之前快速再次单击链接,对话框将再次触发。

    这个问题有什么万无一失的解决办法吗?


    注:以下不是解决方案:

    var alreadyPrompted = false;
    window.onbeforeunload = function(){
        // only prompt if the flag has been set... 
        if(promptBeforeLeaving === true && alreadyPrompted === false){
            alreadyPrompted = true;
            return "Are you sure you want to leave this page?";
        }
    }
    

    因为用户可能会选择“留在页面上”选项,这将导致未来 onbeforeunload 停止工作。

    2 回复  |  直到 11 年前
        1
  •  6
  •   Josiah Ruddell    14 年前

    我想你可以用计时器来完成这个任务( setInterval )开始于 onbeforeunload 回拨。当确认对话框打开时,javascript执行将暂停,然后如果用户取消,则定时函数可以重置 alreadyPrompted 变量返回到false,并清除间隔。

    只是个主意。

    好的,我根据你的意见做了一个快速测试。

    <span id="counter">0</span>
    window.onbeforeunload = function () {
       setInterval(function () { $('#counter').html(++counter); }, 1);
       return "are you sure?";
    }
    window.onunload = function () { alert($('#counter').html()) };
    

    在两次回调之间 #counter 从未超过2(ms)。似乎将这两个回调结合在一起可以满足您的需要。

    编辑-回复评论:

    关闭。我就是这么想的

    var promptBeforeLeaving = true,
        alreadPrompted = false,
        timeoutID = 0,
        reset = function () {
            alreadPrompted = false;
            timeoutID = 0;
        };
    
    window.onbeforeunload = function () {
        if (promptBeforeLeaving && !alreadPrompted) {
            alreadPrompted = true;
            timeoutID = setTimeout(reset, 100);
            return "Changes have been made to this page.";
        }
    };
    
    window.onunload = function () {
        clearTimeout(timeoutID);
    };
    
        2
  •  1
  •   kofifus    11 年前

    我将上述答案封装在一个易于使用的函数中:

    function registerUnload(msg, onunloadFunc) {
        var alreadPrompted = false,
            timeoutID = 0,
            reset = function() {
                alreadPrompted = false;
                timeoutID = 0;
            };
    
        if (msg || onunloadFunc) { // register
            window.onbeforeunload = function() {
                if (msg && !alreadPrompted) {
                    alreadPrompted = true;
                    timeoutID = setTimeout(reset, 100);
                    return msg;
                }
            };
    
            window.onunload = function() {
                clearTimeout(timeoutID);
                if (onunloadFunc) onunloadFunc();
            };
        } else { // unregister
            window.onbeforeunload = null;
            window.onunload = null;
        }
    }
    

    注册使用:

    registerUnload("Leaving page", function() { /* unload work */ });
    

    要注销,请使用:

    registerUnload();
    

    希望这有帮助。