Comment capturer l'événement de fermeture de la fenêtre du navigateur?

149

Je veux capturer l'événement de fermeture de fenêtre / onglet du navigateur. J'ai essayé ce qui suit avec jQuery:

jQuery(window).bind(
    "beforeunload", 
    function() { 
        return confirm("Do you really want to close?") 
    }
)

Mais cela fonctionne également sur la soumission de formulaires, ce qui n'est pas ce que je veux. Je veux un événement qui se déclenche uniquement lorsque l'utilisateur ferme la fenêtre.

khelll
la source

Réponses:

212

L' beforeunloadévénement se déclenche chaque fois que l'utilisateur quitte votre page pour une raison quelconque.

Par exemple, il sera déclenché si l'utilisateur soumet un formulaire, clique sur un lien, ferme la fenêtre (ou l'onglet) ou accède à une nouvelle page à l'aide de la barre d'adresse, de la zone de recherche ou d'un signet.

Vous pouvez exclure les soumissions de formulaire et les liens hypertexte (à l'exception d'autres cadres) avec le code suivant:

var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

Pour les versions de jQuery antérieures à 1.7, essayez ceci:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

La liveméthode ne fonctionne pas avec l' submitévénement, donc si vous ajoutez un nouveau formulaire, vous devrez également lier le gestionnaire à celui-ci.

Notez que si un autre gestionnaire d'événements annule la soumission ou la navigation, vous perdrez l'invite de confirmation si la fenêtre est effectivement fermée plus tard. Vous pouvez résoudre ce problème en enregistrant le temps dans les submitet clickévénements, et vérifier si le beforeunloadproduit plus que quelques secondes plus tard.

SLaks
la source
8
yup, fonctionne très bien! Les nouvelles versions de jquery prennent en charge $ ('form'). Live ('submit, function () {}).
Venkat D.
4
Votre solution est bonne mais comment annuler l'événement en cas d'actualisation? Je veux l'événement uniquement si le navigateur est fermé, pas de cas de rafraîchissement
Refael
Il semble que le navigateur affiche la valeur de retour de beforeunload comme une boîte de dialogue de confirmation. Je pense donc que cette réponse est plus précise: lien
tahagh
2
le fait de rafraîchissement poignée d'une page à l' aide Ctrl + r, F5, Ctrl + Shift + ret changer l'URL du navigateur?
Arti
1
@Jonny: C'est maintenant juste .on().
SLaks
45

Peut-être simplement dissocier le beforeunloadgestionnaire d'événements dans le gestionnaire d'événements du formulaire submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});
karim79
la source
3
N'est-ce pas aussi simple de ne pas utiliser jQuery en le spécifiant dans la définition de la balise de formulaire? : `<form onsubmit =" window.onbeforeunload = null; ">
admiration le
4
@awe Mais vous devez l'inclure onsubmit=...dans chaque formulaire. (J'ai plusieurs formulaires par page, dans une certaine application Web)
KajMagnus
16

Pour une solution multi-navigateurs (testée dans Chrome 21, IE9, FF15), pensez à utiliser le code suivant, qui est une version légèrement modifiée du code de Slaks:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
}); 

Notez que depuis Firefox 4, le message "Voulez-vous vraiment fermer?" n'est pas affiché. FF affiche juste un message générique. Voir la note dans https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload

desm
la source
3
Celui-ci fonctionne de manière cohérente sur tous les navigateurs. Juste un petit mot; J'ai mis à jour à la fois les instructions liveet les bindinstructions to on, ce qui fonctionne très bien avec le dernier niveau de jQuery. Merci!
Sablefoste
16
window.onbeforeunload = function () {
    return "Do you really want to close?";
};
Behnam Mohammadi
la source
4

Pour une solution qui fonctionne bien avec des contrôles tiers comme Telerik (ex: RadComboBox) et DevExpress qui utilisent les balises Anchor pour diverses raisons, envisagez d'utiliser le code suivant, qui est une version légèrement modifiée du code de desm avec un meilleur sélecteur pour soi ciblage des balises d'ancrage:

var inFormOrLink;
$('a[href]:not([target]), a[href][target=_self]').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
});
PLT
la source
1
Cette réponse est correcte, mais pour ceux qui ont eu des problèmes avec cet événement qui se produit lorsque vous actualisez le navigateur, modifiez votre if par le code suivant: if (inFormOrLink! == undefined &&! InFormOrLink)
LeonPierre
4

Ma réponse vise à fournir des repères simples.

COMMENT

Voir la réponse @SLaks .

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

Combien de temps faut-il au navigateur pour finalement fermer votre page?

Chaque fois qu'un utilisateur ferme la page ( xbouton ou CTRL+ W), le navigateur exécute le beforeunloadcode donné , mais pas indéfiniment. La seule exception est la boîte de confirmation ( return 'Do you really want to close?) qui attendra la réponse de l'utilisateur.

Chrome : 2 secondes.
Firefox : ∞ (ou double-cliquez, ou forcez la fermeture)
Edge : ∞ (ou double-cliquez)
Explorer 11 : 0 secondes.
Safari : TODO

Ce que nous avons utilisé pour tester ceci:

  • Un serveur Node.js Express avec journal des requêtes
  • Le court fichier HTML suivant

Ce qu'il fait, c'est envoyer autant de demandes que possible avant que le navigateur ne ferme sa page (de manière synchrone).

<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script>
    function request() {
        return $.ajax({
            type: "GET",
            url: "http://localhost:3030/" + Date.now(),
            async: true
        }).responseText;
    }
    window.onbeforeunload = () => {
        while (true) {
            request();
        }
        return null;
    }
    </script>
</body>
</html>

Sortie Chrome:

GET /1480451321041 404 0.389 ms - 32  
GET /1480451321052 404 0.219 ms - 32  
...  
GET /hello/1480451322998 404 0.328 ms - 32

1957ms  2 seconds // we assume it's 2 seconds since requests can take few milliseconds to be sent.
zurfyx
la source
3

J'ai utilisé la réponse de Slaks mais cela ne fonctionnait pas tel quel, car le returnValue onbeforeunload est analysé sous forme de chaîne puis affiché dans la boîte de confirmation du navigateur. Ainsi, la valeur true était affichée, comme "true".

Le simple fait d'utiliser le retour a fonctionné. Voici mon code

var preventUnloadPrompt;
var messageBeforeUnload = "my message here - Are you sure you want to leave this page?";
//var redirectAfterPrompt = "http://www.google.co.in";
$('a').live('click', function() { preventUnloadPrompt = true; });
$('form').live('submit', function() { preventUnloadPrompt = true; });
$(window).bind("beforeunload", function(e) { 
    var rval;
    if(preventUnloadPrompt) {
        return;
    } else {
        //location.replace(redirectAfterPrompt);
        return messageBeforeUnload;
    }
    return rval;
})
kapad
la source
1

Vous pourriez peut-être gérer OnSubmit et définir un indicateur que vous archiverez plus tard dans votre gestionnaire OnBeforeUnload.

i_am_jorf
la source
1
jQuery(window).bind(
                    "beforeunload",
                      function (e) {
                          var activeElementTagName = e.target.activeElement.tagName;
                          if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
                              return "Do you really want to close?";
                          }
                      })
Homme de codage
la source
1

Malheureusement, qu'il s'agisse d'un rechargement, d'une nouvelle redirection de page ou de la fermeture du navigateur, l'événement sera déclenché. Une alternative est d'attraper l'id déclenchant l'événement et s'il s'agit d'un formulaire, ne déclenchez aucune fonction et si ce n'est pas l'id du formulaire, faites ce que vous voulez faire lorsque la page se ferme. Je ne sais pas si cela est également possible directement et fastidieux.

Vous pouvez faire quelques petites choses avant que le client ne ferme l'onglet. javascript détecte le navigateur fermer l'onglet / fermer le navigateur mais si votre liste d'actions est grande et que l'onglet se ferme avant qu'il ne soit terminé, vous êtes impuissant. Vous pouvez l'essayer, mais avec mon expérience, n'en dépendez pas.

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";
  /* Do you small action code here */
  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload?redirectlocale=en-US&redirectslug=DOM/Mozilla_event_reference/beforeunload

Gary
la source
0

Si votre soumission de formulaire les amène à une autre page (comme je suppose que c'est le cas, d'où le déclenchement de beforeunload), vous pouvez essayer de changer la soumission de votre formulaire en un appel ajax. De cette façon, ils ne quitteront pas votre page lorsqu'ils soumettront le formulaire et vous pourrez utiliser votre beforeunloadcode de liaison comme vous le souhaitez.

idrumgood
la source
0

Mon problème: l'événement «onbeforeunload» ne serait déclenché que s'il y avait un nombre impair de soumissions (clics). J'avais une combinaison de solutions issues de threads similaires dans SO pour que ma solution fonctionne. bien mon code parlera.

<!--The definition of event and initializing the trigger flag--->


$(document).ready(function() {
updatefgallowPrompt(true);
window.onbeforeunload = WarnUser;   
}

function WarnUser() {
var allowPrompt = getfgallowPrompt();
    if(allowPrompt) {
    saveIndexedDataAlert();
    return null;
    } else {
        updatefgallowPrompt(true);
        event.stopPropagation
    }
}

<!--The method responsible for deciding weather the unload event is triggered from submit or not--->
function saveIndexedDataAlert() {
    var allowPrompt = getfgallowPrompt();
    var lenIndexedDocs = parseInt($('#sortable3 > li').size()) + parseInt($('#sortable3 > ul').size());

    if(allowPrompt && $.trim(lenIndexedDocs) > 0) {
        event.returnValue = "Your message";
    } else {
        event.returnValue = "   ";
        updatefgallowPrompt(true);
    }
}

<!---Function responsible to reset the trigger flag---->
$(document).click(function(event) {  
$('a').live('click', function() { updatefgallowPrompt(false); });
 });

<!--getter and setter for the flag---->
function updatefgallowPrompt (allowPrompt){ //exit msg dfds
    $('body').data('allowPrompt', allowPrompt); 
}   

function getfgallowPrompt(){        
    return $('body').data('allowPrompt');   
}
Yoosaf Abdulla
la source
0

Depuis jQuery 1.7, la méthode .live () est obsolète. Utilisez .on () pour attacher des gestionnaires d'événements. Les utilisateurs d'anciennes versions de jQuery devraient utiliser .delegate () de préférence à .live ()

$(window).bind("beforeunload", function() {
    return true || confirm("Do you really want to close?"); 
}); 

sur complet ou lien

$(window).unbind();
À M
la source
0

Essayez ceci aussi

window.onbeforeunload = function ()
{       
    if (pasteEditorChange) {
        var btn = confirm('Do You Want to Save the Changess?');
           if(btn === true ){
               SavetoEdit();//your function call
           }
           else{
                windowClose();//your function call
           }
    }  else { 
        windowClose();//your function call
    }
};
Bhaskara Arani
la source
-1

Vérifiez simplement ...

function wopen_close(){
  var w = window.open($url, '_blank', 'width=600, height=400, scrollbars=no, status=no, resizable=no, screenx=0, screeny=0');
  w.onunload = function(){
    if (window.closed) {
       alert("window closed");
    }else{ 
       alert("just refreshed");
    }
  }
}
Brunno
la source
Ça ne marche pas. Au moment où l'événement de déchargement se déclenche (btw, il se déclenche à partir du document), le window.closed === false;
Sergey P. aka azure
-1
var validNavigation = false;
            jQuery(document).ready(function () {

                wireUpEvents();
            });

            function endSession() {
                // Browser or broswer tab is closed
                // Do sth here ...
                alert("bye");
            }

            function wireUpEvents() {
                /*
                * For a list of events that triggers onbeforeunload on IE
                * check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
                */
                window.onbeforeunload = function () {
                    debugger
                    if (!validNavigation) {
                        endSession();
                    }
                }

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

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

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

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

            }`enter code here`
Arslan Khan
la source
-7

La suite a fonctionné pour moi;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });
Dilhan Jayathilaka
la source
c'est une fonction jquery.
maxisam
7
Le event.clientYest négatif si vous cliquez sur le bouton de fermeture du navigateur ou sur le bouton de fermeture de l'onglet. Cependant, cette valeur est positive lorsque vous rechargez la page à l'aide des raccourcis clavier (F5, Ctrl-R) ou fermez le navigateur à l'aide des raccourcis clavier (par exemple Alt-F4). Ainsi, vous ne pouvez pas vous fier à la position de l'événement pour différencier l'événement de fermeture du navigateur de l'événement de rechargement de page.
Julien Kronegg