是否有任何跨浏览器的JavaScript/jQuery代码来检测浏览器或浏览器标签是否正在关闭,但不是由于链接被单击?


当前回答

I have tried all above solutions, none of them really worked for me, specially because there are some Telerik components in my project which have 'Close' button for popup windows, and it calls 'beforeunload' event. Also, button selector does not work properly when you have Telerik grid in your page (I mean buttons inside the grid) So, I couldn't use any of above suggestions. Finally this is the solution worked for me. I have added an onUnload event on the body tag of _Layout.cshtml. Something like this:

<body onUnload="LogOff()">

然后添加LogOff函数重定向到Account/LogOff,这是Asp中的内置方法。净MVC。现在,当我关闭浏览器或选项卡,它重定向到LogOff方法和用户必须登录时返回。我已经在Chrome和Firefox中进行了测试。它确实有效!

  function LogOff() {
        $.ajax({
            url: "/Account/LogOff",
            success: function (result) {

                                        }
               });
       }

其他回答

onunload是Chrome的答案。根据caniuse它的交叉浏览器。但并非所有浏览器的反应都一样。

window.onunload = function(){
    alert("The window is closing now!");
}

developer.mozilla.org

这些事件在窗口卸载其内容和资源时触发。

铬:

Onunload只在页面关闭时执行。它甚至不会在页面刷新和导航到另一个页面时执行。

Firefox v86.0版本:

它根本不会执行。页面刷新,导航离开,关闭浏览器标签,关闭浏览器,什么都没有。

来自MDN文档

由于某些原因,基于webkit的浏览器不符合对话框的规范。一个几乎交叉工作的例子与下面的例子很接近。

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";

  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

本例处理所有浏览器。

我找到了一个方法,在我所有的浏览器上都能运行。

测试在以下版本: Firefox 57, Internet Explorer 11, Edge 41,最新的Chrome浏览器之一(无法显示我的版本)

注意:onbeforeunload火灾如果你离开页面以任何可能的方式(刷新,关闭浏览器,重定向,链接,提交..)。如果只希望它在浏览器关闭时发生,只需绑定事件处理程序。

  $(document).ready(function(){         

        var validNavigation = false;

        // Attach the event keypress to exclude the F5 refresh (includes normal refresh)
        $(document).bind('keypress', function(e) {
            if (e.keyCode == 116){
                validNavigation = true;
            }
        });

        // Attach the event click for all links in the page
        $("a").bind("click", function() {
            validNavigation = true;
        });

        // Attach the event submit for all forms in the page
        $("form").bind("submit", function() {
          validNavigation = true;
        });

        // Attach the event click for all inputs in the page
        $("input[type=submit]").bind("click", function() {
          validNavigation = true;
        }); 

        window.onbeforeunload = function() {                
            if (!validNavigation) {     
                // ------->  code comes here
            }
        };

  });

I have tried all above solutions, none of them really worked for me, specially because there are some Telerik components in my project which have 'Close' button for popup windows, and it calls 'beforeunload' event. Also, button selector does not work properly when you have Telerik grid in your page (I mean buttons inside the grid) So, I couldn't use any of above suggestions. Finally this is the solution worked for me. I have added an onUnload event on the body tag of _Layout.cshtml. Something like this:

<body onUnload="LogOff()">

然后添加LogOff函数重定向到Account/LogOff,这是Asp中的内置方法。净MVC。现在,当我关闭浏览器或选项卡,它重定向到LogOff方法和用户必须登录时返回。我已经在Chrome和Firefox中进行了测试。它确实有效!

  function LogOff() {
        $.ajax({
            url: "/Account/LogOff",
            success: function (result) {

                                        }
               });
       }

浏览器已经进行了更新,以便在用户离开应用程序时更好地调整用户。事件“visibilitychange”让你在页面从另一个选项卡隐藏或关闭时进行调整。您可以跟踪文档可见性状态。财产文件。visbilitystate将返回当前状态。您将需要跟踪标志的进出,但它更接近目标。

更新的浏览器支持这一点,但safari(正如我们所知)从来不符合标准。你可以使用' pagshow '和'pagehide'在safari中工作。

您甚至可以使用像sendBeacon这样的新API在标签关闭时向服务器发送单向请求,并且不应该期待响应。

我构建了一个类的快速端口,用于跟踪此情况。我不得不删除框架中的一些调用,所以它可能是bug,但这应该让你开始。

export class UserLoginStatus
{
    /**
     * This will add the events and sign the user in.
     */
    constructor()
    {
        this.addEvents();
        this.signIn();
    }

    /**
     * This will check if the browser is safari. 
     * 
     * @returns {bool}
     */
    isSafari()
    {
        if(navigator && /Safari/.test(navigator.userAgent) && /Chrome/.test(navigator.userAgent))
        {
            return (/Google Inc/.test(navigator.vendor) === false);
        }
        return false;
    }

    /**
     * This will setup the events array by browser.
     * 
     * @returns {array}
     */
    setupEvents()
    {
        let events = [
            ['visibilitychange', document, () =>
            {
                if (document.visibilityState === 'visible')
                {
                    this.signIn();
                    return;
                }

                this.signOut();
            }]
        ];

        // we need to setup events for safari
        if(this.isSafari())
        {
            events.push(['pageshow', window, (e) =>
            {
                if(e.persisted === false)
                {
                    this.signIn();
                }
            }]);

            events.push(['pagehide', window, (e) =>
            {
                if(e.persisted === false)
                {
                    this.signOut();
                }
            }]);
        }

        return events;
    }

    /**
     * This will add the events.
     */
    addEvents()
    {
        let events = this.setupEvents();
        if(!events || events.length < 1)
        {
            return;
        }

        for(var i = 0, length = events.length; i < length; i++)
        {
            var event = events[i];
            if(!event)
            {
                continue;
            }

            event[1].addEventListener(event[0], event[3]);
        }
    }

    /**
     * 
     * @param {string} url 
     * @param {string} params 
     */
    async fetch(url, params)
    {
        await fetch(url, 
        {
            method: 'POST',
            body: JSON.stringify(params)
        });
    }

    /**
     * This will sign in the user.
     */
    signIn()
    {
        // user is the app
        const url = '/auth/login';
        let params = 'userId=' + data.userId;

        this.fetch(url, params);
    }

    /**
     * This will sign out the user.
     */
    signOut()
    {
        // user is leaving the app

        const url = '/auth/logout';
        let params = 'userId=' + data.userId;

        if(!('sendBeacon' in window.navigator))
        {
            // normal ajax request here
            this.fetch(url, params);
            return;
        }

        // use a beacon for a more modern request the does not return a response
        navigator.sendBeacon(url, new URLSearchParams(params));
    }
}