Comment détecter un événement avec le bouton Précédent du navigateur-navigateur croisé

Comment détecter définitivement si l'utilisateur A ou non appuyé sur le bouton arrière du navigateur?

comment imposer l'utilisation d'un bouton d'Arrière-page à l'intérieur d'une application web d'une page unique en utilisant un système #URL ?

Pourquoi diable n'avez pas de navigateur boutons de retour d'incendie de leurs propres événements!?

124
demandé sur Xarus 2014-09-12 14:50:50

9 réponses

(Note: selon les commentaires de Sharky, j'ai inclus le code pour détecter les espaces)

donc, j'ai vu ces questions fréquemment sur SO, et ont récemment couru dans la question du contrôle de la fonctionnalité bouton arrière moi-même. Après quelques jours de recherche de la meilleure solution pour mon application (simple Page avec navigation Hash), j'ai trouvé un simple, cross-browser, bibliothèque sans système pour détecter le bouton arrière.

la plupart des gens recommande d'utiliser:

window.onhashchange = function() {
 //blah blah blah
}

cependant, cette fonction sera aussi appelée lorsqu'un utilisateur utilise l'élément on in-page qui change le hachage d'emplacement. Pas la meilleure expérience utilisateur lorsque votre utilisateur clique et la page va en arrière ou en avant.

Pour vous donner un aperçu général de mon système, je suis remplissage d'un tableau avec les précédents hachages que mon utilisateur se déplace à travers l'interface. Il ressemble à quelque chose comme ceci:

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

Assez simple et directe. Je le fais pour assurer la prise en charge de tous les navigateurs, ainsi que la prise en charge des navigateurs plus anciens. Il suffit de passer le nouveau hachage à la fonction, et il va le stocker pour vous, puis changer le hachage (qui est ensuite mis dans l'histoire du navigateur).

j'utilise aussi un bouton de retour de page qui déplace l'utilisateur entre les pages en utilisant le tableau lasthash . Il ressemble à ceci:

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

donc cela va déplacer l'utilisateur de nouveau au dernier hachage, et retirez ce dernier hachage du tableau (je n'ai pas de bouton avant en ce moment).

So. Comment puis-je déterminer si un utilisateur a utilisé le bouton Précédent ou le bouton du navigateur?

au début , j'ai regardé window.onbeforeunload , mais en vain - cela est seulement appelé si l'utilisateur va changer les pages. Cela ne se produit pas dans une application d'une seule page utilisant la navigation hash.

donc, après avoir creusé un peu plus, j'ai vu des recommandations pour essayer de définir un indicateur de la variable. Le problème avec cela dans mon cas, c'est que j'essaierais de le régler, mais comme tout est asynchrone, il ne serait pas toujours réglé à temps pour la déclaration de si dans le changement de hachage. .onMouseDown n'était pas toujours appelé en click, et l'ajouter à un clic ne le déclencherait jamais assez vite.

C'est quand j'ai commencé à regarder la différence entre document , et window . Ma solution finale a été de mettre le drapeau en utilisant document.onmouseover , et le désactiver en utilisant document.onmouseleave .

ce qui se passe est que pendant que la souris de l'utilisateur est à l'intérieur de la zone de document (lire: la page rendue, mais en excluant le cadre du navigateur), mon booléen est réglé à true . Dès que la souris quitte la zone des documents, le booléen passe à false .

de cette façon, je peux changer mon window.onhashchange en:

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

vous noterez le chèque pour #undefined . C'est parce que si il n'y a pas d'histoire disponibles dans mon tableau, il retourne undefined . Je l'utilise pour demander à l'utilisateur s'il souhaite quitter l'aide d'un window.onbeforeunload de l'événement.

donc, en bref, et pour les gens qui ne sont pas nécessairement en utilisant un bouton arrière page ou un tableau pour stocker l'histoire:

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

et voilà. un moyen simple et en trois parties de détecter l'utilisation du bouton arrière par rapport aux éléments de la page en ce qui concerne la navigation hash.

Modifier:

pour vous assurer que l'utilisateur n'utilise pas backspace pour déclencher l'événement de retour, vous pouvez également inclure ce qui suit (merci à @thetoolman sur cette Question ):

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});
125
répondu Xarus 2017-10-18 08:40:44

vous pouvez essayer popstate event handler, E. g:

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

Note: pour les meilleurs résultats, vous devez charger ce code seulement sur des pages spécifiques où vous voulez mettre en œuvre la logique pour éviter tout autre problème inattendu.

l'événement popstate est déclenché à chaque fois que l'entrée courante change (l'utilisateur navigue vers un nouvel état). Qui se produit lorsque l'utilisateur clique sur navigateur Boutons arrière / avant ou quand history.back() , history.forward() , history.go() les méthodes sont programmatiquement appelées.

Le event.state est la propriété de l'événement est égale à l'histoire de l'état de l'objet.

Pour jQuery syntaxe, l'enrouler autour d' (pour ajouter de la même écouteur d'après le document est prêt):

(function($) {
  // Above code here.
})(jQuery);

voir aussi: fenêtre.onpopstate au chargement de la page


Voir aussi les exemples sur Single-Page Apps et HTML5 pushState page:

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

cela doit être compatible avec Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ et similaire.

46
répondu kenorb 2017-05-23 12:34:50

j'avais été aux prises avec cette exigence pendant un certain temps et j'ai pris certaines des solutions ci-dessus pour la mettre en œuvre. Cependant, je suis tombé sur une observation et il semble fonctionner à travers Chrome, Firefox et Safari navigateurs + Android et iPhone

sur le chargement de page:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

dites-moi si ça peut aider. Si je rate quelque chose, je serai heureux de comprendre.

9
répondu Itzmeygu 2017-08-22 11:56:11

navigateur: https://jsfiddle.net/Limitlessisa/axt1Lqoz /

pour la commande mobile: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show /

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>
2
répondu Limitless isa 2016-10-19 15:38:03

voilà ce que je pense. L'hypothèse est que, lorsque L'URL change mais qu'il n'y a pas de clic dans le document détecté, c'est un retour de navigateur (oui, ou en avant). Un clic d'utilisateur est réinitialisé après 2 secondes pour faire ce travail sur les pages qui chargent le contenu via Ajax:

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);
2
répondu TomTom101 2017-02-17 10:37:50

le document.mouseover ne fonctionne pas pour IE et FireFox. Cependant j'ai essayé ceci:

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

cela fonctionne pour Chrome et IE et pas FireFox. Je travaille toujours pour avoir FireFox. N'importe quel moyen facile pour détecter le bouton de retour/avant du navigateur sont les bienvenus, pas particulièrement dans JQuery mais aussi AngularJS ou Javascript simple.

1
répondu Dhruv Gupta 2015-04-21 07:14:46

Je l'ai résolu en gardant la trace de l'événement original qui a déclenché le hashchange (que ce soit un balayage, un clic ou une roue), de sorte que l'événement ne serait pas confondu avec un simple atterrissage sur la page, et en utilisant un drapeau supplémentaire dans chacune de mes fixations d'événement. Le navigateur ne remettra pas le drapeau à false en appuyant sur le bouton arrière:

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}
0
répondu Niccolò Mineo 2018-04-14 17:11:02
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });
0
répondu Ashwin 2018-07-17 19:24:18

j'ai essayé les options ci-dessus, mais aucune ne fonctionne pour moi. Voici la solution

if(window.event)
   {
        if(window.event.clientX < 40 && window.event.clientY < 0)
        {
            alert("Browser back button is clicked...");
        }
        else
        {
            alert("Browser refresh button is clicked...");
        }
    }

Consultez ce lien http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli pour plus de détails

-13
répondu Sures Ramar 2016-05-12 12:48:27