Y a-t-il un événement de chargement entre navigateurs lorsque vous cliquez sur le bouton Précédent?

185

Pour tous les principaux navigateurs (à l'exception d'IE), l' onloadévénement JavaScript ne se déclenche pas lorsque la page se charge à la suite d'une opération sur le bouton de retour - il se déclenche uniquement lorsque la page est chargée pour la première fois.

Quelqu'un peut-il m'indiquer un exemple de code multi-navigateurs (Firefox, Opera, Safari, IE,…) qui résout ce problème? Je connais l' pageshowévénement de Firefox mais malheureusement, ni Opera ni Safari ne l'implémentent.

Facture
la source
6
Ce n'est pas un problème - cela permet à la page Web d'être chargée rapidement lorsque l'utilisateur appuie sur le bouton Retour. Voir ma réponse ci-dessous pour plus de détails. Les solutions de contournement suggérées ici rendent la page Web plus ennuyeuse pour l'utilisateur, car la navigation en arrière / en avant est plus lente.
Nickolay
2
@romkyns: votre commentaire n'est pas lié à cette question. Lorsque les navigateurs ne restaurent pas l'état JS / DOM, ils déclenchent l'événement load.
Nickolay
Bouton de retour de l'historique iOS 5+ résolu ici stackoverflow.com/a/12652160/1090395
Mladen Janjetovic

Réponses:

117

Les gars, j'ai trouvé que JQuery n'a qu'un seul effet: la page est rechargée lorsque le bouton de retour est enfoncé. Cela n'a rien à voir avec « prêt ».

Comment cela marche-t-il? Eh bien, JQuery ajoute un écouteur d' événement onunload .

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

Par défaut, il ne fait rien. Mais d'une manière ou d'une autre, cela semble déclencher un rechargement dans Safari, Opera et Mozilla - quel que soit le contenu du gestionnaire d'événements.

[ modifier (Nickolay) : voici pourquoi cela fonctionne de cette façon: webkit.org , developer.mozilla.org . Veuillez lire ces articles (ou mon résumé dans une réponse distincte ci-dessous) et déterminer si vous avez vraiment besoin de le faire et ralentir le chargement de votre page pour vos utilisateurs.]

Tu ne peux pas y croire? Essaye ça:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

Vous verrez des résultats similaires lors de l'utilisation de JQuery.

Vous voudrez peut-être comparer à celui-ci sans téléchargement

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>
user123444555621
la source
1
Très bien .. bien que ce soit une fonctionnalité / bogue non documentée, et pourrait simplement cesser de fonctionner dans les futures versions du navigateur, mais c'est toujours intéressant.
Wadih M.
3
Cela fonctionne aussi (n'oubliez pas la partie onunload = "", sinon ne fonctionnera pas sur ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.
3
Cela est dû au fait que le navigateur suppose que la page est indisponible si elle a un onunloadgestionnaire (la page a déjà tout détruit; pourquoi la mettre en cache?).
Casey Chu
14
La réponse ne semble pas fonctionner dans les navigateurs modernes - vérifié dans les derniers Chrome et Opera
Andrew
10
cela ne fonctionne pas dans le safari iPad ... s'il vous plaît, décochez ceci comme réponse
xus
74

Certains navigateurs modernes (Firefox, Safari et Opera, mais pas Chrome) prennent en charge le cache spécial "arrière / avant" (je l'appellerai bfcache, qui est un terme inventé par Mozilla), impliqué lorsque l'utilisateur navigue en arrière. Contrairement au cache normal (HTTP), il capture l'état complet de la page (y compris l'état de JS, DOM). Cela lui permet de recharger la page plus rapidement et exactement comme l'utilisateur l'a laissée.

le load événement n'est pas censé se déclencher lorsque la page est chargée à partir de ce bfcache. Par exemple, si vous avez créé votre interface utilisateur dans le gestionnaire "load" et que l'événement "load" a été déclenché une fois lors du chargement initial et la deuxième fois lorsque la page a été rechargée à partir du bfcache, la page se retrouverait avec dupliquer les éléments de l'interface utilisateur.

C'est aussi pourquoi l'ajout du gestionnaire "unload" arrête le stockage de la page dans le bfcache (rendant ainsi la navigation plus lente vers) - le gestionnaire de déchargement pourrait effectuer des tâches de nettoyage, ce qui pourrait laisser la page dans un état irréalisable.

Pour les pages qui ont besoin de savoir quand elles sont en cours de navigation ou de retour, Firefox 1.5+ et la version de Safari avec le correctif du bogue 28758 prennent en charge les événements spéciaux appelés «pageshow» et «pagehide».

Références:

Nickolay
la source
C'est très cool. Je suis actuellement dans une situation où mes manipulations dom ne semblent pas être enregistrées dans le bfcache. Y a-t-il des situations où vous pourriez vous attendre à cela?
Benson
1
@Benson: les raisons possibles pour lesquelles Firefox ne sauvegardera pas votre page dans bfcache sont répertoriées sur la page dev.mo à laquelle j'ai lié. Je ne pense pas qu'il soit possible d'enregistrer la page sur bfcache, mais certains états DOM ne sont pas enregistrés.
Nickolay
Nickolay, je comprends votre réticence à forcer un rechargement et à annuler le bon travail effectué par le bfcache, mais y a-t-il un autre moyen de mettre à jour le dom de la page dans le bfcache? Par exemple, considérons la situation où je passe d'une page contenant une liste de messages à l'un d'entre eux, et lorsque je retourne "en arrière", je veux que l'indicateur lu / non lu change. Comment cela peut-il être fait sans recharger la page?
Greg
@Greg: vous voulez dire en tant que développeur contrôlant la page? Lancez une requête ajax à partir d'un auditeur 'pageshow'.
Nickolay
Des idées sur la façon d'utiliser jQuery ET d'obtenir un support rapide de bfcache?
Alex Black
31

J'ai rencontré un problème que mon js ne s'exécutait pas lorsque l'utilisateur avait cliqué en arrière ou en avant. J'ai d'abord décidé d'arrêter la mise en cache du navigateur, mais cela ne semblait pas être le problème. Mon javascript a été configuré pour s'exécuter après le chargement de toutes les bibliothèques, etc. Je les ai vérifiés avec l'événement readyStateChange.

Après quelques tests, j'ai découvert que le readyState d'un élément dans une page où le retour a été cliqué n'est pas «chargé» mais «complet». Ajouter|| element.readyState == 'complete' à ma déclaration conditionnelle a résolu mes problèmes.

Je pensais juste partager mes découvertes, j'espère qu'elles aideront quelqu'un d'autre.

Modifier pour l'exhaustivité

Mon code ressemblait à ceci:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

Dans l'exemple de code ci-dessus, la variable de script était un élément de script nouvellement créé qui avait été ajouté au DOM.

Brian Heese
la source
7
Où avez-vous ajouté cela? Et comment avez-vous fait tirer quoi que ce soit après que l'utilisateur a répondu? Veuillez nous montrer un code!
Keerigan
Que voulez-vous dire quand vous dites «ma déclaration conditionnelle»?
Phillip Senn
1
@Phillip Une instruction conditionnelle est une instruction if.
Brian Heese
22

OK, voici une solution finale basée sur la solution initiale de ckramer et l'exemple de palehorse qui fonctionne dans tous les navigateurs, y compris Opera. Si vous définissez history.navigationMode sur `` compatible '', la fonction Ready de jQuery se déclenchera sur les opérations du bouton Retour dans Opera ainsi que sur les autres principaux navigateurs.

Cette page contient plus d'informations .

Exemple:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

J'ai testé cela dans Opera 9.5, IE7, FF3 et Safari et cela fonctionne dans tous.

Facture
la source
2
Évidemment, cela fait un moment (environ 5,5 ans) mais il convient de noter que votre lien est mort.
Jeff
2
Cette solution ne fonctionne pas pour moi. J'ai ce problème dans la dernière version de Firefox (45.0.1)
Armin
6

Je n'ai pas pu faire fonctionner les exemples ci-dessus. Je voulais simplement déclencher un rafraîchissement de certaines zones div modifiées en revenant à la page via le bouton retour. L'astuce que j'ai utilisée était de définir un champ de saisie caché (appelé "bit sale") à 1 dès que les zones div changées de l'original. Le champ de saisie masqué conserve en fait sa valeur lorsque je clique en arrière, donc onload je peux vérifier ce bit. S'il est défini, j'actualise la page (ou je rafraîchis simplement les divs). Sur le chargement d'origine, cependant, le bit n'est pas défini, donc je ne perds pas de temps à charger la page deux fois.

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

Et cela se déclencherait correctement chaque fois que je cliquais sur le bouton de retour.

thorie
la source
3
Bien que cela ne fonctionne pas dans Firefox, je pense que c'est un moyen astucieux de gérer la situation dans IE / Chrome où la persistance du champ caché est très utile. J'ai utilisé votre astuce et aussi l'événement "pageshow", donc je couvre tous les principaux navigateurs.
Magnus Smith
Quel navigateur ne fonctionne pas avec les pages, comment cela fonctionne-t-il?
Justin
4

Si je me souviens bien, l'ajout d'un événement unload () signifie que la page ne peut pas être mise en cache (dans le cache avant / arrière) - car son état change / peut changer lorsque l'utilisateur s'éloigne. Donc, il n'est pas sûr de restaurer l'état de dernière seconde de la page en y retournant en naviguant dans l'objet d'historique.


la source
4

Je pensais que ce serait pour "onunload", pas pour le chargement de la page, car ne parlons-nous pas de déclencher un événement en appuyant sur "Back"? $ document.ready () est pour les événements souhaités lors du chargement de la page, peu importe comment vous accédez à cette page (c'est-à-dire rediriger, ouvrir le navigateur directement vers l'URL, etc.), pas lorsque vous cliquez sur "Retour", sauf si vous parlez sur ce qu'il faut déclencher sur la page précédente lorsqu'il se charge à nouveau. Et je ne suis pas sûr que la page ne soit pas mise en cache car j'ai constaté que les Javascripts le sont toujours, même lorsque $ document.ready () y est inclus. Nous avons dû appuyer sur Ctrl + F5 lors de l'édition de nos scripts qui ont cet événement chaque fois que nous les révisons et nous voulons tester les résultats dans nos pages.

$(window).unload(function(){ alert('do unload stuff here'); }); 

est ce que vous voudriez pour un événement onunload lorsque vous appuyez sur "Retour" et déchargez la page en cours, et se déclenche également lorsqu'un utilisateur ferme la fenêtre du navigateur. Cela ressemblait plus à ce qui était souhaité, même si je suis en infériorité numérique avec les réponses $ document.ready (). Fondamentalement, la différence est entre un événement qui se déclenche sur la page en cours lors de sa fermeture ou sur celui qui se charge lorsque vous cliquez sur "Retour" pendant son chargement. Testé dans IE 7 très bien, je ne peux pas parler pour les autres navigateurs car ils ne sont pas autorisés où nous sommes. Mais cela pourrait être une autre option.

À M
la source
4

Je peux confirmer à ckramer que l'événement ready de jQuery fonctionne dans IE et FireFox. Voici un exemple:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>
cheval pâle
la source
4

pour les personnes qui ne veulent pas utiliser toute la bibliothèque jquery, j'ai extrait l'implémentation dans un code séparé. Il ne fait que 0,4 Ko.

Vous pouvez trouver le code, ainsi qu'un tutoriel en allemand dans ce wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

Torben Brodt
la source
1
Un lien isolé est considéré comme une mauvaise réponse (voir FAQ ) car il n'a pas de sens en soi et la ressource cible n'est pas garantie d'être vivante dans le futur . Il serait préférable d'inclure ici les parties essentielles de la réponse et de fournir le lien pour référence.
j0k
3

L' événement ready de jQuery a été créé pour ce type de problème. Vous voudrez peut-être creuser dans l'implémentation pour voir ce qui se passe sous les couvertures.

ckramer
la source
6
Bien longtemps après, readyne semble pas se déclencher dans Firefox, lors de l'utilisation du bouton Retour. Voir aussi la réponse de Nickolay .
Arjan
2

Bill, j'ose répondre à votre question, mais je ne suis pas sûr à 100% de mes suppositions. Je pense que d'autres navigateurs IE, lorsqu'ils amènent l'utilisateur vers une page de l'historique, chargeront non seulement la page et ses ressources à partir du cache, mais ils restaureront également l'état complet du DOM (session de lecture) pour elle. IE ne fait pas de restauration DOM (ou au bail ne l'a pas fait) et donc l'événement onload semble être nécessaire pour une réinitialisation correcte de la page.

Sergey Ilinsky
la source
2

J'ai essayé la solution de Bill en utilisant $ (document) .ready ... mais au début cela n'a pas fonctionné. J'ai découvert que si le script est placé après la section html, cela ne fonctionnera pas. Si c'est la section principale, cela fonctionnera mais uniquement dans IE. Le script ne fonctionne pas dans Firefox.

Johann
la source
1

OK, j'ai essayé cela et cela fonctionne dans Firefox 3, Safari 3.1.1 et IE7 mais pas dans Opera 9.52.
Si vous utilisez l'exemple ci-dessous (basé sur l'exemple de palehorse), vous obtenez une boîte d'alerte lorsque la page se charge pour la première fois. Mais si vous accédez ensuite à une autre URL, puis appuyez sur le bouton Retour pour revenir à cette page, vous n'obtenez pas de boîte d'alerte dans Opera (mais vous le faites dans les autres navigateurs).

Quoi qu'il en soit, je pense que c'est assez proche pour le moment. Merci tout le monde!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>
Facture
la source
1

L'événement de déchargement ne fonctionne pas correctement sur IE 9. Je l'ai essayé avec l'événement de chargement (onload ()), il fonctionne bien sur IE 9 et FF5 .

Exemple:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>
Mallesham
la source
0

J'ai utilisé un modèle html. Dans le fichier custom.js de ce modèle, il y avait une fonction comme celle-ci:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

Mais cette fonction ne fonctionnait pas lorsque je reviens en arrière après être allé à une autre page.

Donc, j'ai essayé ceci et cela a fonctionné:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

Maintenant, j'ai 2 fonctions «prêt» mais cela ne donne aucune erreur et la page fonctionne très bien.

Néanmoins, je dois déclarer qu'il a testé sur Windows 10 - Opera v53 et Edge v42 mais pas d'autres navigateurs. Gardez à l'esprit ceci ...

Remarque: la version de jquery était 3.3.1 et la version de migration était 3.0.0

bafsar
la source